You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Java的Cucumber:Gherkin特性文件失败后立即重跑方案咨询

解决方案:基于JUnit4 TestRule实现Scenario级立即重试

针对Cucumber 7 + JUnit4环境下的失败Scenario立即重跑需求,可通过自定义JUnit TestRule拦截测试执行流程,实现失败后立即重试,同时保证BeforeAll/AfterAll仅执行一次。

实现步骤

1. 编写自定义重试规则类

该类负责拦截每个Scenario的执行,在失败时触发立即重试,直到达到最大重试次数:

import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;

public class CucumberRetryRule implements TestRule {
    // 最大重试次数
    private static final int MAX_RETRY = 2;

    @Override
    public Statement apply(Statement base, Description description) {
        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                Throwable lastFailure = null;

                for (int retryCount = 0; retryCount <= MAX_RETRY; retryCount++) {
                    try {
                        // 执行当前Scenario
                        base.evaluate();
                        return; // 测试成功,终止重试
                    } catch (Throwable t) {
                        lastFailure = t;
                        System.err.printf("Scenario [%s] 失败,第 %d 次重试中...%n", 
                            description.getDisplayName(), retryCount + 1);
                    }
                }
                // 所有重试失败,抛出最后一次异常
                throw lastFailure;
            }
        };
    }
}

2. 配置Cucumber生命周期钩子

确保BeforeAll和AfterAll仅执行一次,在步骤定义包下创建钩子类:

import io.cucumber.java.AfterAll;
import io.cucumber.java.BeforeAll;

public class SuiteHooks {
    @BeforeAll
    public static void beforeAll() {
        System.out.println("执行BeforeAll()");
        // 全局初始化逻辑
    }

    @AfterAll
    public static void afterAll() {
        System.out.println("执行AfterAll()");
        // 全局清理逻辑
    }
}

3. 修改Cucumber Runner类

引入重试规则,并确保钩子类在Cucumber的扫描路径中:

import org.junit.Rule;
import org.junit.runner.RunWith;
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
import java.util.stream.Stream;

@RunWith(Cucumber.class)
@CucumberOptions(
        tags = "@xxx",
        plugin = {"pretty"},
        features = {"classpath:features"},
        glue = {"StepDefinitions", "your.package.path"} // 替换为包含SuiteHooks的包路径
)
public class Runner {
    // 注册重试规则
    @Rule
    public CucumberRetryRule retryRule = new CucumberRetryRule();

    private static String[] defaultOptions = {
            "classpath:features",
            "--glue", "StepDefinitions",
            "--tags", "@xxx",
            "--plugin", "pretty",
    };

    public static void main(String[] args) {
        Stream<String> cucumberOptions = Stream.concat(Stream.of(defaultOptions), Stream.of(args));
        ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
        byte exitStatus = io.cucumber.core.cli.Main.run(cucumberOptions.toArray(String[]::new), contextClassLoader);

        // 自定义PDF报告逻辑
    }
}

流程验证

该方案完全符合你的预期流程:

  1. 所有Scenario执行前,仅执行一次BeforeAll()
  2. 每个Scenario执行前触发@Before(步骤定义中的非静态钩子)
  3. 执行Scenario,失败则立即重试,最多2次
  4. 每次Scenario(含重试)执行后触发@After
  5. 所有Scenario执行完成后,执行AfterAll()

关键说明

  • JUnit4的TestRule会自动拦截Cucumber生成的每个Scenario测试方法,实现粒度精准的重试控制
  • 无需依赖已弃用的Cucumber EventListener,完全适配Cucumber 7.x版本
  • 可关闭Maven Surefire的rerunFailingTestsCount参数,避免重复重试

内容的提问来源于stack exchange,提问作者user22334850

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 00:54:55