SpringBoot应用中复用Feature文件运行两套Cucumber步骤定义的方案
解决方案:同一Feature适配本地/远程两套Cucumber步骤定义
核心问题分析
Cucumber默认只扫描glue参数指定包下的@DataTableType类,当新旧步骤定义分属不同包时,新步骤所在包无法扫描到原有的类型转换类,导致Feature数据转Java对象失败。同时需要通过标签区分执行逻辑,分离Maven构建与部署后测试任务。
1. 共享类型转换定义
将@DataTableType类抽离到公共包,让两套步骤定义都能扫描到:
package com.example.common; import io.cucumber.java.DataTableType; import com.example.model.User; import java.util.Map; public class CommonDataTableTypes { @DataTableType public User userEntry(Map<String, String> entry) { return new User( entry.get("id"), entry.get("name") ); } }
2. 给步骤定义打标签区分
给本地、远程步骤定义分别添加标签,避免步骤重复冲突:
本地步骤定义(集成SpringBoot)
package com.example.steps.local; import io.cucumber.java.Tag; import io.cucumber.spring.CucumberContextConfiguration; import org.springframework.boot.test.context.SpringBootTest; import io.cucumber.java.en.Given; import com.example.model.User; @Tag("local") @CucumberContextConfiguration @SpringBootTest public class LocalSteps { @Given("用户存在") public void userExists(User user) { // 本地测试逻辑:直接操作Spring上下文 } }
远程步骤定义(REST调用Dev环境)
package com.example.steps.remote; import io.cucumber.java.Tag; import io.cucumber.java.en.Given; import com.example.model.User; import org.springframework.web.client.RestTemplate; @Tag("remote") public class RemoteSteps { private final RestTemplate restTemplate = new RestTemplate(); @Given("用户存在") public void userExists(User user) { // 远程测试逻辑:调用Dev环境REST接口 restTemplate.postForObject("http://dev.example.com/users", user, User.class); } }
3. 配置独立测试套件
创建两个JUnit Suite类,分别指定对应步骤包、公共类型转换包及标签过滤:
本地测试套件
package com.example.test; import org.junit.platform.suite.api.ConfigurationParameter; import org.junit.platform.suite.api.IncludeEngines; import org.junit.platform.suite.api.SelectPackages; import org.junit.platform.suite.api.Suite; import static io.cucumber.junit.platform.engine.Constants.*; @Suite @IncludeEngines("cucumber") @SelectPackages("com.example.features") // 指定Feature文件所在包 @ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "com.example.steps.local,com.example.common") @ConfigurationParameter(key = TAGS_PROPERTY_NAME, value = "@local") public class LocalTestSuite { }
远程测试套件
package com.example.test; import org.junit.platform.suite.api.ConfigurationParameter; import org.junit.platform.suite.api.IncludeEngines; import org.junit.platform.suite.api.SelectPackages; import org.junit.platform.suite.api.Suite; import static io.cucumber.junit.platform.engine.Constants.*; @Suite @IncludeEngines("cucumber") @SelectPackages("com.example.features") @ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "com.example.steps.remote,com.example.common") @ConfigurationParameter(key = TAGS_PROPERTY_NAME, value = "@remote") public class RemoteTestSuite { }
4. Maven配置分离执行
通过Maven插件和Profile,让本地测试在构建阶段自动执行,远程测试作为独立任务触发:
<build> <plugins> <!-- 本地测试:Maven构建时自动执行 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>3.0.0-M7</version> <configuration> <includes> <include>**/LocalTestSuite.java</include> </includes> </configuration> <executions> <execution> <phase>test</phase> <goals> <goal>test</goal> </goals> </execution> </executions> </plugin> <!-- 远程测试:通过Profile触发 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-failsafe-plugin</artifactId> <version>3.0.0-M7</version> <configuration> <includes> <include>**/RemoteTestSuite.java</include> </includes> </configuration> </plugin> </plugins> </build> <profiles> <profile> <id>remote-tests</id> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-failsafe-plugin</artifactId> <executions> <execution> <phase>integration-test</phase> <goals> <goal>integration-test</goal> <goal>verify</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </profile> </profiles>
执行方式
- 本地测试:运行
mvn test,构建阶段自动执行本地Suite - 远程测试:部署后运行
mvn verify -P remote-tests,触发远程Suite执行
内容的提问来源于stack exchange,提问作者Prashant Bhardwaj
相关产品推荐
相关产品推荐

