I can perform actions on test failure by using:
@After
public void afterTest(Scenario scenario) {
if (scenario.isFailed()) {
/*Do stuff*/
}
}
However some of the actions I need to perform depend on the Exception that was thrown and in what context it was thrown. Is there a way to get the Throwable that caused the test to fail? For example in JUnit I would do this by extending TestWatcher and add a rule to my tests:
@Override
protected void failed(Throwable e, Description description) {
/*Do stuff with e*/
}
However the cucumber-junit iplementation does not allow the use of rules, so this solution would not work with Cucumber.
I don't think I need to explain why accessing a thrown exception on test failure would be useful, however I will still provide an Example:
My test environment is not always stable, so my tests might fail unexpectedly at any moment (there's no specific place I can try to catch the exception since it could occur at any time). When this happens I need the test to reschedule for another attempt, and log the incident so that we can get some good statistical data on the environment instability (when, how frequent, how long etc.)
We can run this file by right click on it just like the testng. xml file and it will execute only failed test cases. Another approach is by using the rerun plugin option in the runner class. To use this we need to modify our existing Runner class.
Cucumber skips all steps after a failed step by design. Once a step has failed, the test has failed and there should be no reason to perform the next steps. If you have a need to run the additional steps, likely your scenario is testing too many different things at once.
To run the specific tags only, run the command mvn test -Dcucumber. options="--tags @SmokeTest" on command prompt. It will run only tags, which are marked with @SmokeTest. In order to change the format of the result, run the command E:\Workspace\LoginTest>mvn test -Dcucumber.
The problem with the work around suggested by Frank Escobar:
By using reflection to reach into a frameworks internals you're depending on implementation details. This is a bad practice, when ever the framework changes its implementation your code may break as you will observe in Cucumber v5.0.0.
Hooks in Cucumber are designed to manipulate the test execution context before and after a scenario. They're not made to report on the test execution itself. Reporting is cross cutting concern and best managed by using the plugin system.
For example:
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());
}
}
When using JUnit 4 and TestNG you can activate this plugin using:
@CucumberOptions(plugin="com.example.MyTestListener")
With JUnit 5 you add it to junit-platform.properties
:
cucumber.plugin=com.example.MyTestListener
Or if you are using the CLI
--plugin com.example.MyTestListener
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With