如何获取在 Java 中 Cucumber 测试失败时抛出的异常?

EJS*_*EJS 6 java cucumber

我可以使用以下方法对测试失败执行操作:

@After
public void afterTest(Scenario scenario) {
    if (scenario.isFailed()) {
        /*Do stuff*/
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,我需要执行的某些操作取决于抛出的异常以及抛出的上下文。有没有办法获得导致测试失败的 Throwable?例如在 JUnit 中,我会通过扩展 TestWatcher 并在我的测试中添加规则来做到这一点:

@Override
protected void failed(Throwable e, Description description) {
    /*Do stuff with e*/
}
Run Code Online (Sandbox Code Playgroud)

但是,cucumber-junit 实施不允许使用规则,因此该解决方案不适用于 Cucumber。

我认为我不需要解释为什么在测试失败时访问抛出的异常会很有用,但是我仍然会提供一个示例:

我的测试环境并不总是稳定的,所以我的测试可能在任何时候意外失败(没有特定的地方我可以尝试捕获异常,因为它随时可能发生)。发生这种情况时,我需要重新安排测试以进行另一次尝试,并记录事件,以便我们可以获得一些关于环境不稳定的良好统计数据(何时、多频繁、多长时间等)

mpk*_*nje 12

Frank Escobar 建议的解决方法存在的问题:

通过使用反射来了解框架内部,您依赖于实现细节。这是一个不好的做法,当框架更改其实现时,您的代码可能会中断,正如您在 Cucumber v5.0.0 中观察到的那样。

Cucumber 中的钩子旨在在场景之前和之后操作测试执行上下文。它们并不是用来报告测试执行本身的。报告是跨领域的问题,最好通过使用插件系统进行管理。

例如:

package com.example;

import io.cucumber.plugin.ConcurrentEventListener;
import io.cucumber.plugin.event.EventPublisher;
import io.cucumber.plugin.event.Result;
import io.cucumber.plugin.event.Status;
import io.cucumber.plugin.event.TestCase;
import io.cucumber.plugin.event.TestCaseFinished;

public class MyTestListener implements ConcurrentEventListener {
    @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();
        Status status = result.getStatus();
        Throwable error = result.getError();
        String scenarioName = testCase.getName();
        String id = "" + testCase.getUri() + testCase.getLine();
        System.out.println("Testcase " + id + " - " + status.name());
    }
}
Run Code Online (Sandbox Code Playgroud)

使用 JUnit 4 和 TestNG 时,您可以使用以下方法激活此插件:

@CucumberOptions(plugin="com.example.MyTestListener")
Run Code Online (Sandbox Code Playgroud)

使用 JUnit 5,您可以将其添加到junit-platform.properties

cucumber.plugin=com.example.MyTestListener 
Run Code Online (Sandbox Code Playgroud)

或者如果您使用的是 CLI

cucumber.plugin=com.example.MyTestListener 
Run Code Online (Sandbox Code Playgroud)


Fra*_*bar 5

我已经使用反射实现了这个方法。您无法直接访问步骤错误(堆栈跟踪)。我创建了这个静态方法,它允许您访问“stepResults”属性,然后您可以迭代并获取错误并做任何您想做的事情。

import cucumber.runtime.ScenarioImpl; 
import gherkin.formatter.model.Result;  
import org.apache.commons.lang3.reflect.FieldUtils;  
import java.lang.reflect.Field;  
import java.util.ArrayList;

@After
public void afterScenario(Scenario scenario) {
  if (scenario.isFailed())
    logError(scenario);
}


private static void logError(Scenario scenario) {
   Field field = FieldUtils.getField(((ScenarioImpl) scenario).getClass(), "stepResults", true);
   field.setAccessible(true);
   try {
       ArrayList<Result> results = (ArrayList<Result>) field.get(scenario);
       for (Result result : results) {
           if (result.getError() != null)
               LOGGER.error("Error Scenario: {}", scenario.getId(), result.getError());
       }
   } catch (Exception e) {
       LOGGER.error("Error while logging error", e);
   }
}
Run Code Online (Sandbox Code Playgroud)


Gra*_*per 2

您可以通过编写自己的自定义Formatter & Reporter接口实现来实现这一点。的空实现FormatterNullFormatter.java您可以扩展的。您将需要提供该Reporter接口的实现。

感兴趣的方法是result()Reporter 接口的方法,也可能done()是 Formatter 的方法。result() 具有Result存在异常的对象。

你可以看清楚RerunFormatter.java

Github 格式化程序源

public void result(Result result) {
      //Code to create logs or store to a database etc...
      result.getError();
      result.getErrorMessage();
}
Run Code Online (Sandbox Code Playgroud)

您需要将此类(com.myimpl.CustomFormRep)添加到插件选项中。

plugin={"pretty", "html:report", "json:reports.json","rerun:target/rerun.txt",com.myimpl.CustomFormRep}
Run Code Online (Sandbox Code Playgroud)

有关自定义格式化程序的更多详细信息。

您可以使用重新运行插件来获取失败场景的列表以再次运行。不确定如何安排运行失败的测试、创建批处理作业的代码或在 CI 工具上安排一个运行。