Java语言Cucumber API技术问询:获取特征/标签及运行子集并封装REST接口
Java中Cucumber API实现需求方案
结合你提供的Cucumber 7.16.1版本依赖,完全可以通过Cucumber自身API和JUnit Platform相关工具实现你需要的三个功能,以下是具体实现方案:
1. 获取Feature文件列表及包含的Scenarios
使用Cucumber的FeatureParser和ClasspathResourceLoader加载并解析Feature文件,示例代码如下:
import io.cucumber.core.feature.FeatureParser; import io.cucumber.core.resource.ClasspathResourceLoader; import io.cucumber.core.resource.Resource; import io.cucumber.core.resource.ResourceLoader; import io.cucumber.messages.types.Feature; import io.cucumber.messages.types.Scenario; import java.net.URI; import java.util.ArrayList; import java.util.List; public class FeatureScanner { public List<FeatureInfo> scanFeatures() { List<FeatureInfo> featureInfos = new ArrayList<>(); ResourceLoader resourceLoader = new ClasspathResourceLoader(getClass().getClassLoader()); // 扫描classpath下所有.feature文件,可指定路径如"classpath:features/**/*.feature" resourceLoader.resources("classpath:**/*.feature", resource -> { Feature feature = parseFeature(resource); List<String> scenarioNames = feature.getScenarioDefinitions().stream() .filter(def -> def instanceof Scenario) .map(def -> ((Scenario) def).getName()) .toList(); featureInfos.add(new FeatureInfo(feature.getName(), resource.getUri().toString(), scenarioNames)); return true; }); return featureInfos; } private Feature parseFeature(Resource resource) { try { return FeatureParser.parse(resource.getUri(), resource.getInputStream()); } catch (Exception e) { throw new RuntimeException("解析Feature文件失败: " + resource.getUri(), e); } } // 自定义DTO用于返回Feature信息 public static class FeatureInfo { private String featureName; private String featurePath; private List<String> scenarioNames; public FeatureInfo(String featureName, String featurePath, List<String> scenarioNames) { this.featureName = featureName; this.featurePath = featurePath; this.scenarioNames = scenarioNames; } // getter方法 public String getFeatureName() { return featureName; } public String getFeaturePath() { return featurePath; } public List<String> getScenarioNames() { return scenarioNames; } } }
2. 获取所有Tags列表
在解析Feature文件的过程中,提取Feature和Scenario级别的Tags并去重,基于上面的FeatureScanner扩展实现:
import java.util.HashSet; import java.util.Set; public Set<String> getAllTags() { Set<String> tags = new HashSet<>(); ResourceLoader resourceLoader = new ClasspathResourceLoader(getClass().getClassLoader()); resourceLoader.resources("classpath:**/*.feature", resource -> { Feature feature = parseFeature(resource); // 添加Feature级Tags feature.getTags().forEach(tag -> tags.add(tag.getName())); // 添加Scenario级Tags feature.getScenarioDefinitions().stream() .filter(def -> def instanceof Scenario) .map(def -> ((Scenario) def).getTags()) .flatMap(List::stream) .forEach(tag -> tags.add(tag.getName())); return true; }); return tags; }
3. 按名称或Tags运行指定子集
利用JUnit Platform Launcher API,结合Cucumber配置参数指定运行范围,示例代码如下:
import org.junit.platform.engine.discovery.DiscoverySelectors; import org.junit.platform.launcher.Launcher; import org.junit.platform.launcher.LauncherDiscoveryRequest; import org.junit.platform.launcher.core.LauncherFactory; import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder; import io.cucumber.junit.platform.engine.Constants; import java.util.List; public class CucumberTestRunner { public void runSpecifiedTests(List<String> featurePaths, List<String> tags, List<String> scenarioNames) { LauncherDiscoveryRequestBuilder requestBuilder = LauncherDiscoveryRequestBuilder.request(); // 指定要运行的Feature文件路径 if (!featurePaths.isEmpty()) { featurePaths.forEach(path -> requestBuilder.selectors(DiscoverySelectors.selectClasspathResource(path))); } // 配置Tags筛选规则 if (!tags.isEmpty()) { String tagExpression = String.join(" or ", tags.stream().map(tag -> "@" + tag).toList()); requestBuilder.configurationParameter(Constants.FILTER_TAGS_PROPERTY_NAME, tagExpression); } // 配置Scenario名称筛选(支持正则匹配) if (!scenarioNames.isEmpty()) { String namePattern = String.join("|", scenarioNames); requestBuilder.configurationParameter(Constants.FILTER_NAME_PROPERTY_NAME, namePattern); } LauncherDiscoveryRequest request = requestBuilder.build(); Launcher launcher = LauncherFactory.create(); // 可自定义TestExecutionListener收集运行结果 launcher.execute(request); } }
封装为REST端点
基于Spring Boot创建CucumberController暴露REST接口,示例如下:
import org.springframework.web.bind.annotation.*; import java.util.List; import java.util.Set; @RestController @RequestMapping("/cucumber") public class CucumberController { private final FeatureScanner featureScanner = new FeatureScanner(); private final CucumberTestRunner testRunner = new CucumberTestRunner(); @GetMapping("/features") public List<FeatureScanner.FeatureInfo> getFeatures() { return featureScanner.scanFeatures(); } @GetMapping("/tags") public Set<String> getTags() { return featureScanner.getAllTags(); } @PostMapping("/run") public void runTests(@RequestBody TestRunRequest request) { testRunner.runSpecifiedTests(request.getFeaturePaths(), request.getTags(), request.getScenarioNames()); } // 自定义请求DTO public static class TestRunRequest { private List<String> featurePaths; private List<String> tags; private List<String> scenarioNames; // getter/setter方法 public List<String> getFeaturePaths() { return featurePaths; } public void setFeaturePaths(List<String> featurePaths) { this.featurePaths = featurePaths; } public List<String> getTags() { return tags; } public void setTags(List<String> tags) { this.tags = tags; } public List<String> getScenarioNames() { return scenarioNames; } public void setScenarioNames(List<String> scenarioNames) { this.scenarioNames = scenarioNames; } } }
注意事项
- 你的
pom.xml已包含所有必要依赖:cucumber-java、cucumber-junit-platform-engine、junit-platform-launcher,无需额外添加。 - 若需要收集测试运行结果,可自定义
org.junit.platform.launcher.TestExecutionListener并注册到Launcher中,获取测试的成功/失败状态、耗时等信息。 - Feature文件路径建议使用classpath相对路径,如
features/user/Login.feature。
内容的提问来源于stack exchange,提问作者florin
相关产品推荐
相关产品推荐

