Cucumber:参数类型与配置详解

参数类型:让Cucumber参数"活"起来

参数类型可以将Cucumber表达式中的参数自动转换为自定义对象,就像给参数"穿上马甲",让它们变成程序能直接使用的类型。

核心概念

  • 参数类型:将表达式参数转换为对象

  • 数据表/文档字符串类型:将表格或多行文本转换为对象

  • 自动检测:放在胶水代码路径下,Cucumber会自动发现它们

三种自定义类型转换方式

1. 数据表类型(DataTableType) - 表格变对象

将数据表中的每一行转换为自定义对象:

java 复制代码
package com.example;

import io.cucumber.java.DataTableType;
import io.cucumber.java.en.Given;
import java.util.List;
import java.util.Map;

public class StepDefinitions {

    @DataTableType
    public Author authorEntry(Map<String, String> entry) {
        // 把表格行映射成Author对象
        return new Author(
            entry.get("firstName"),
            entry.get("lastName"),
            entry.get("famousBook"));
    }

    @Given("以下是我最喜欢的作者")
    public void these_are_my_favourite_authors(List<Author> authors) {
        // 现在authors是Author对象列表,不是原始数据
        authors.forEach(author -> System.out.println(author.getName()));
    }
}
2. 参数类型(ParameterType) - 表达式参数变对象

将步骤中的参数转换为特定类型:

java 复制代码
package com.example;

import io.cucumber.java.ParameterType;
import io.cucumber.java.en.Given;

public class StepDefinitions {

    @ParameterType(".*")  // 匹配任何文本
    public Book book(String bookName) {
    	return new Book(bookName);  // 将字符串转换为Book对象
    }

    @Given("{book}是我最喜欢的书")
    public void this_is_my_favorite_book(Book book) {
        // book已经是Book对象,可以直接调用方法
        System.out.println("我最喜欢的书:" + book.getTitle());
    }
}
3. 文档字符串类型(DocStringType) - 多行文本变对象

将多行文本(如JSON、XML)转换为对象:

java 复制代码
package com.example;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.cucumber.java.DocStringType;
import io.cucumber.java.en.Given;

public class StepsDefinitions {

    private static ObjectMapper objectMapper = new ObjectMapper();

    @DocStringType
    public JsonNode json(String docString) throws JsonProcessingException {
        // 将JSON字符串转换为JsonNode对象
        return objectMapper.readValue(docString, JsonNode.class);
    }

    @Given("书籍信息由JSON定义")
    public void books_are_defined_by_json(JsonNode books) {
        // books已经是解析好的JSON对象
        System.out.println("书籍数量:" + books.size());
    }
}

Lambda风格的实现方式

如果你喜欢更简洁的Lambda表达式:

java 复制代码
package com.example;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.cucumber.java8.En;
import java.util.Map;

public class LambdaStepDefinitions implements En {

    private static ObjectMapper objectMapper = new ObjectMapper();

    public LambdaStepDefinitions() {
        // Lambda风格的类型注册
        DataTableType((Map<String, String> entry) -> new Author(
            entry.get("firstName"),
            entry.get("lastName"),
            entry.get("famousBook")
        ));

        ParameterType("book", ".*", (String bookName) -> new Book(bookName));

        DocStringType("json", (String docString) ->
            objectMapper.readValue(docString, JsonNode.class));
    }
}

通用转换器 - 让Jackson等库自动处理

如果不想为每个类型都写转换逻辑,可以使用通用转换器:

java 复制代码
package com.example;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.cucumber.java.DefaultDataTableCellTransformer;
import io.cucumber.java.DefaultDataTableEntryTransformer;
import io.cucumber.java.DefaultParameterTransformer;
import java.lang.reflect.Type;

public class StepDefinitions {

    private final ObjectMapper objectMapper = new ObjectMapper();

    @DefaultParameterTransformer
    @DefaultDataTableEntryTransformer
    @DefaultDataTableCellTransformer
    public Object transformer(Object fromValue, Type toValueType) {
        // 让Jackson自动处理所有转换
        return objectMapper.convertValue(fromValue, 
            objectMapper.constructType(toValueType));
    }
}

Lambda风格的通用转换器:

java 复制代码
package com.example;

import io.cucumber.java8.En;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.lang.reflect.Type;

public class LambdaStepDefinitions implements En {

    public LambdaStepDefinitions() {
        ObjectMapper objectMapper = new ObjectMapper();

        DefaultParameterTransformer((String fromValue, Type toValueType) ->
            objectMapper.convertValue(fromValue, 
                objectMapper.constructType(toValueType)));

        DefaultDataTableCellTransformer((fromValue, toValueType) ->
            objectMapper.convertValue(fromValue, 
                objectMapper.constructType(toValueType)));

        DefaultDataTableEntryTransformer((fromValue, toValueType) ->
            objectMapper.convertValue(fromValue, 
                objectMapper.constructType(toValueType)));
    }
}

错误提示

如果使用了未定义的类型,会看到清晰的错误信息:

复制代码
The parameter type "person" is not defined.
(参数类型"person"未定义。)

配置:让测试适应不同环境

配置文件(Profiles)- Java版的特殊处理

Cucumber-JVM本身不支持配置文件功能,但可以通过构建工具来实现类似效果。

Maven配置示例:为不同环境设置不同标签
java 复制代码
<profiles>
    <profile>
        <id>dev</id>  <!-- 开发环境 -->
        <properties>
            <!-- 只运行@dev标签,跳过@ignore标签 -->
            <cucumber.filter.tags>@dev and not @ignore</cucumber.filter.tags>
        </properties>
    </profile>
    <profile>
        <id>qa</id>  <!-- 测试环境 -->
        <properties>
            <!-- 只运行@qa标签 -->
            <cucumber.filter.tags>@qa</cucumber.filter.tags>
        </properties>
    </profile>
</profiles>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>3.0.0-M4</version>
            <configuration>
                <systemPropertyVariables>
                    <!-- 将Maven属性传递给Cucumber -->
                    <cucumber.filter.tags>${cucumber.filter.tags}</cucumber.filter.tags>
                </systemPropertyVariables>
            </configuration>
        </plugin>
    </plugins>
</build>
使用方式
bash 复制代码
# 运行开发环境的测试
mvn test -Pdev

# 运行测试环境的测试  
mvn test -Pqa
Gradle的替代方案

Gradle可以通过任务配置来实现类似效果,具体参考Gradle文档中的"Maven profiles and properties迁移"部分。

环境变量

重要说明 :Cucumber-JVM不支持通过.env文件配置环境变量。如果需要设置环境相关配置,可以通过:

  1. 系统属性(如上例中的Maven配置)

  2. 操作系统的环境变量

  3. 配置文件读取


通俗理解:参数类型就像"翻译官"

参数类型的实际意义

想象一下你去国外餐厅点餐:

  • 没有参数类型:服务员给你一本全是外文的菜单,你得自己查字典

  • 有参数类型:服务员直接给你中文菜单,还帮你推荐菜品

配置文件的实际应用场景

  • 开发环境:只想运行自己正在开发的测试,不想跑全部

  • 测试环境:QA团队只想运行冒烟测试或回归测试

  • 生产前:运行所有测试,确保一切正常

简单记忆口诀

  1. 参数类型:字符串变对象,测试更轻松

  2. 数据表类型:表格数据直接转,省去解析麻烦

  3. 文档字符串:JSON/XML自动解析,拿来就能用

  4. 配置分离:不同环境不同测试,灵活又方便

实际工作流程

复制代码
编写特性文件 → Cucumber解析参数 → 自定义类型转换 → 得到业务对象 → 执行测试断言
    (Given/When/Then)  ↓                 ↓
                     (字符串)   →  (Author/Book等对象)

这样设计的好处是:测试代码更简洁,业务逻辑更清晰,维护成本更低

相关推荐
qq_338032922 小时前
Vue/JS项目的package.json文件 和java项目里面的pom文件
java·javascript·vue.js·json
霸道流氓气质2 小时前
Java 实现折线图整点数据补全与标准化处理示例代码讲解
java·开发语言·windows
jason.zeng@15022072 小时前
spring boot mqtt开发-原生 Paho 手动封装(最高灵活性,完全自定义)
java·spring boot·后端
sunnyday04262 小时前
Filter、Interceptor、Spring AOP 的执行顺序详解
java·spring boot·后端·spring
想用offer打牌2 小时前
一站式了解Spring AI Alibaba的Memory机制
java·人工智能·后端·spring·chatgpt·系统架构
打工的小王2 小时前
Langchain4j(二)RAG知识库
java·后端·ai·语言模型
Remember_9932 小时前
【数据结构】Java对象比较全解析:从equals到Comparable与Comparator,再到PriorityQueue应用
java·开发语言·数据结构·算法·leetcode·哈希算法
沛沛老爹2 小时前
从Web到AI:多模态Agent Skills生态系统实战(Java+Vue构建跨模态智能体)
java·前端·vue.js·人工智能·rag·企业转型