Tests only earn their keep if failures get noticed. A green build that silently hides a flaky test suite is worse than no test suite at all. Good reporting turns raw pass/fail data into actionable information — which scenarios failed, what the response body was, which screenshot shows the broken UI, and how the failure rate trends over time.
Cucumber supports multiple reporting layers simultaneously. This lesson covers the full range: from the built-in HTML report to the enterprise-grade Allure dashboard.
Built-in Cucumber reports
Cucumber's plugin system is configured in the runner class:
@ConfigurationParameter(
key = PLUGIN_PROPERTY_NAME,
value = "pretty, " +
"html:target/cucumber-reports/report.html, " +
"json:target/cucumber-reports/report.json, " +
"junit:target/cucumber-reports/report.xml"
)pretty— coloured step-by-step output in the console with pass/fail indicatorshtml:path— a standalone HTML file viewable in any browser; includes feature file names, scenario names, step statuses, embedded screenshotsjson:path— machine-readable JSON; the input format for third-party reporting toolsjunit:path— JUnit XML; consumed by CI servers (Jenkins, GitHub Actions) for test result trends
All four can be active simultaneously. The JSON report is the most useful output — every other tool reads it.
cucumber-reporting: rich HTML from JSON
The masterthought cucumber-reporting library takes the JSON output and produces a rich HTML dashboard with charts, trend tracking, and pass/fail breakdowns by feature:
<plugin>
<groupId>net.masterthought</groupId>
<artifactId>maven-cucumber-reporting</artifactId>
<version>5.8.1</version>
<executions>
<execution>
<id>generate-reports</id>
<phase>verify</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/cucumber-html-reports</outputDirectory>
<inputDirectory>${project.build.directory}/cucumber-reports</inputDirectory>
<jsonFiles>
<param>**/report.json</param>
</jsonFiles>
<projectName>BDD Test Suite</projectName>
<buildNumber>${env.BUILD_NUMBER}</buildNumber>
</configuration>
</execution>
</executions>
</plugin>Run mvn verify to generate the report after tests complete. The output is a multi-page HTML site at target/cucumber-html-reports/overview-features.html. The overview shows pass/fail percentages per feature. The feature detail page shows each scenario and step.
Allure: the enterprise reporting tool
Allure is the most feature-rich option: interactive reports with filtering, history tracking, environment info, and support for attachments. The Cucumber 7 integration requires one dependency:
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-cucumber7-jvm</artifactId>
<version>2.25.0</version>
<scope>test</scope>
</dependency>Register it as a Cucumber plugin:
@ConfigurationParameter(
key = PLUGIN_PROPERTY_NAME,
value = "pretty, " +
"html:target/cucumber-reports/report.html, " +
"io.qameta.allure.cucumber7jvm.AllureCucumber7Jvm"
)Allure writes JSON results to target/allure-results/ during the test run. Generate the HTML report:
allure serve target/allure-results # opens browser immediately
allure generate target/allure-results -o target/allure-report # writes to diskAllure reads Gherkin structure natively — features appear as test suites, scenarios as test cases, steps with their status. Screenshots attached via scenario.attach(...) appear in the test detail view.
ExtentReports: the popular alternative
ExtentReports is widely used in the Selenium world and has a Cucumber adapter:
<dependency>
<groupId>tech.grasshopper</groupId>
<artifactId>extentreports-cucumber7-adapter</artifactId>
<version>1.14.0</version>
<scope>test</scope>
</dependency>Configuration file src/test/resources/extent.properties:
extent.reporter.spark.start=true
extent.reporter.spark.out=target/extent-reports/index.htmlPlugin registration:
@ConfigurationParameter(
key = PLUGIN_PROPERTY_NAME,
value = "pretty, " +
"html:target/cucumber-reports/report.html, " +
"com.aventstack.extentreports.cucumber.adapter.ExtentCucumberAdapter:"
)Note the trailing colon on the ExtentReports plugin class name — it is required.
Attaching screenshots in reports
Screenshots attached via Scenario.attach() are embedded automatically in Allure, the Cucumber HTML report, and ExtentReports. The key is always in the @After hook:
@After
public void afterScenario(Scenario scenario) {
WebDriver driver = context.getDriver();
if (scenario.isFailed() && driver != null) {
byte[] screenshot = ((TakesScreenshot) driver)
.getScreenshotAs(OutputType.BYTES);
scenario.attach(screenshot, "image/png", scenario.getName());
}
context.quitDriver();
}For Allure, you can also attach the page source for deep debugging:
if (scenario.isFailed() && driver != null) {
// Screenshot
byte[] screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES);
scenario.attach(screenshot, "image/png", "screenshot");
// Page source
String pageSource = driver.getPageSource();
scenario.attach(pageSource.getBytes(), "text/html", "page-source");
}Choosing a reporter
Configuring CI to publish reports
GitHub Actions example — publish Allure reports to GitHub Pages:
- name: Run tests
run: mvn test -Dcucumber.filter.tags="@regression" -Dheadless=true
- name: Generate Allure Report
if: always()
run: allure generate target/allure-results -o target/allure-report --clean
- name: Publish to GitHub Pages
if: always()
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: target/allure-reportif: always() ensures the report is generated and published even when tests fail — which is exactly when you need it most. The JUnit XML report (junit:target/...) published alongside is consumed by GitHub's native test result display.
⚠️ Common mistakes
- Not generating the Allure report before opening it.
allure servestreams results fromtarget/allure-results/— if you opentarget/allure-results/directly in a browser, you see raw JSON files. Always runallure serveorallure generatefirst. - Missing the trailing colon on the ExtentReports plugin string.
com.aventstack.extentreports.cucumber.adapter.ExtentCucumberAdapter:— the colon is part of the plugin configuration syntax for adapters. Without it, ExtentReports silently doesn't activate. testFailureIgnoreabsent in Surefire when tests fail. By default, Maven stops the build on test failure before theverifyphase runs, somaven-cucumber-reportingnever executes. Add<testFailureIgnore>true</testFailureIgnore>to Surefire in CI pipelines where you want reports even from failing builds.- Screenshot MIME type mismatch.
scenario.attach(bytes, "image/jpeg", "name")when the screenshot is actually PNG (Selenium's default) causes the image not to render in some reporters. Always use"image/png"forOutputType.BYTESscreenshots.
🎯 Practice task
Set up all three reporting layers and compare their output. 45 minutes.
- Add all three plugins to the runner:
pretty,html:target/cucumber-reports/report.html,json:target/cucumber-reports/report.json, andAllureCucumber7Jvm. - Add
maven-cucumber-reportingtopom.xml. Runmvn verify— opentarget/cucumber-html-reports/overview-features.htmland browse the feature breakdown. - Run
allure serve target/allure-results— compare the Allure view with the masterthought view. Note which shows more detail per step. - Fail one scenario deliberately (break an assertion). Run again. Confirm the screenshot appears embedded in all three report formats.
- Add the
junit:target/cucumber-reports/report.xmlplugin. Open the XML and find the<testcase>element for your failed scenario — this is what CI parsers read. - Stretch: add the
<testFailureIgnore>true</testFailureIgnore>flag to Surefire and runmvn verifywith a failing test. ConfirmBUILD SUCCESSis reported while the reports still show the failure — the correct CI pattern for "run all tests, publish results, then fail the pipeline based on the JUnit XML".
This completes Chapter 4. Chapter 5 covers BDD in practice with stakeholders — Three Amigos, living documentation, and how to scale BDD on a real team.