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

如何在Cucumber中获取失败Scenario的错误信息及报错行号

Cucumber获取失败场景错误信息及行号的解决方案

针对你遇到的三个问题,直接给出可行的解决方法和代码修改:


1. 存储失败场景的错误信息与行号

Cucumber并行执行时场景会在独立线程中运行,用ThreadLocal存储错误信息能避免线程冲突,确保每个场景的错误数据独立。修改你的TestListener类:

public class TestListener implements ConcurrentEventListener {
    // 线程本地变量,存储每个场景的错误、名称和报错行号
    public static final ThreadLocal<Throwable> SCENARIO_ERROR = new ThreadLocal<>();
    public static final ThreadLocal<String> SCENARIO_NAME = new ThreadLocal<>();
    public static final ThreadLocal<Integer> ERROR_LINE_NUMBER = new ThreadLocal<>();

    @Override
    public void setEventPublisher(EventPublisher publisher) {
        publisher.registerHandlerFor(TestCaseFinished.class, this::handleTestCaseFinished);
    }

    private void handleTestCaseFinished(TestCaseFinished event) {
        TestCase testCase = event.getTestCase();
        Result result = event.getResult();
        SCENARIO_NAME.set(testCase.getName());

        if (result.getStatus() == Status.FAILED) {
            Throwable error = result.getError();
            SCENARIO_ERROR.set(error);
            
            // 从错误栈中提取步骤定义的报错行号(需替换为你的步骤类包名)
            if (error != null) {
                for (StackTraceElement element : error.getStackTrace()) {
                    if (element.getClassName().startsWith("com.yourpackage.steps")) {
                        ERROR_LINE_NUMBER.set(element.getLineNumber());
                        break;
                    }
                }
            }
        } else {
            // 非失败场景清空变量,避免内存泄漏
            SCENARIO_ERROR.remove();
            ERROR_LINE_NUMBER.remove();
        }
    }
}

2. 解决EventPublisher传入null的错误

你不需要手动调用setEventPublisher,Cucumber会自动管理监听器的生命周期并注入有效的EventPublisher实例。直接删除以下错误代码:

// 删掉这两行代码
EventPublisher eventPublisher = null;
setEventPublisher(eventPublisher);

然后需要让Cucumber识别你的监听器:

  • 在src/test/resources下创建cucumber.properties文件,添加:
    cucumber.plugin=com.yourpackage.TestListener
    
  • 或者在JUnit运行器类中配置:
    @CucumberOptions(plugin = {"com.yourpackage.TestListener"})
    public class CucumberTestRunner {}
    

3. 解决Scenario无getError()方法的问题

Cucumber的Scenario接口确实没有提供getError()方法,需要从监听器的ThreadLocal变量中获取错误信息。修改你的@After钩子:

@After
public void nameCatcher(Scenario scenario) throws Exception {
    if (seleniumCore.driver != null) {
        seleniumCore.driver.quit();
    }

    if(scenario.isFailed()) {
        testRailAPItBean.setExecutionResultStatus(TestRailAPIConst.TEST_FAILED);
        
        // 从监听器的线程变量中获取错误数据
        Throwable error = TestListener.SCENARIO_ERROR.get();
        Integer errorLine = TestListener.ERROR_LINE_NUMBER.get();
        String scenarioName = TestListener.SCENARIO_NAME.get();

        // 将错误信息和行号存入变量或上传到TestRail
        if (error != null) {
            String errorDetails = error.getMessage() + " (报错行号: " + errorLine + ")";
            testRailAPItBean.setErrorDetails(errorDetails);
        }
    } else if (scenario.getStatus() == Status.PASSED) {
         testRailAPItBean.setExecutionResultStatus(TestRailAPIConst.TEST_PASSED);
    }
    TestrailRestApi.updateTestCaseResulForTheLastActiveRun();

    // 清空线程变量,防止内存泄漏
    TestListener.SCENARIO_ERROR.remove();
    TestListener.ERROR_LINE_NUMBER.remove();
    TestListener.SCENARIO_NAME.remove();
}

优化Gradle配置

移除重复依赖,替换为JUnit Platform兼容的Cucumber依赖:

plugins {
    id("java")
}

group = "org.example"
version = "master-SNAPSHOT"

repositories {
    mavenCentral()
}

dependencies {
    testImplementation(platform("org.junit:junit-bom:5.9.1"))
    testImplementation("org.junit.jupiter:junit-jupiter")
    testImplementation ("io.cucumber:cucumber-java:7.13.0")
    testImplementation ("io.cucumber:cucumber-junit-platform-engine:7.13.0")
}

tasks.test {
    useJUnitPlatform()
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 19:16:05