Browse the Knowledge Hub211 resources

Serenity BDD review: tutorial, pros and cons
Serenity BDD is an open source Java library for automated acceptance tests. It runs on top of JUnit or Cucumber, records every step a test takes, and turns the results into living documentation organised by requirement. It also provides the Screenplay pattern and integrations with Selenium, Playwright, Appium and REST Assured. It is free under the Apache 2.0 licence.
QAble has evaluated this tool and works alongside it. The factual sections are complete; our view is bounded to what we have actually seen rather than a long-term verdict.
- last reviewed
- 13 October 2026
- version covered
- Serenity BDD 5
- licence
- Open source
At a glance
Serenity BDD at a glance
- Vendor
- Serenity BDD project
- Category
- BDD frameworks, Web automation
- Licence
- Open source (Apache 2.0)
- Platforms
- JVM (Java 17 or later), Chrome, Firefox, Edge, Appium
- Languages
- Java, Gherkin
- Integrates with
- Cucumber, JUnit 5 and 6, Selenium, Playwright, REST Assured, Appium, Maven, Gradle
- First released
- 2011
- Version reviewed
- Serenity BDD 5
Verdict
Our verdict on Serenity BDD
Strengths
- Reports read as living documentation, organised by capability and feature rather than by test class
- Every step, screenshot and REST call is recorded, so a failure can usually be understood from the report alone
- The Screenplay pattern composes small reusable tasks and questions, which scales better than page objects on large suites
- Works over Cucumber or JUnit, with Selenium, Playwright, Appium and REST Assured integrations in one model
- WebDriver lifecycle, driver downloads and browser configuration handled through serenity.conf
- Free and open source under Apache 2.0
Weaknesses
- Screenplay has a real learning curve, and mixed styles in one suite become hard to follow
- The HTML report needs a separate aggregate step, so a plain mvn test produces no Serenity report
- Most current development is driven by commercial support contracts, which slows unfunded fixes
- Java 17 or later from Serenity 5, and a heavier dependency stack than plain JUnit or Cucumber
Our take
Serenity BDD earns its place on Java teams that want test results to read as documentation of the product, organised by capability and feature, with screenshots and every step recorded, and that are willing to adopt its conventions to get there. Its reporting is far richer than plain Cucumber or JUnit output, and the Screenplay pattern scales better than page objects on large suites once a team has learned it. QAble has evaluated Serenity rather than maintained a long-running suite on it, so treat this as a bounded take. Three things to weigh: the learning curve of Screenplay, the extra build steps that produce the report, and the project’s statement that most current development is driven by commercial support contracts, so issues that matter to you may need a paid package to be prioritised.
We have evaluated this tool rather than maintained a long-running suite on it, so this is a bounded view rather than a long-term verdict. The rest of this page is factual.
How it works
What is Serenity BDD and how does it work?
Instrumented steps and JSON outcomes
Serenity instruments your test code so that it can record what happens inside a test, not just whether it passed. Methods annotated with @Step in action classes, Screenplay tasks and interactions, and Cucumber steps all become entries in the test’s outcome, with their parameters, timing, screenshots and any REST requests and responses. During the run Serenity writes these outcomes as JSON files under target/site/serenity. That separation matters: the run itself only produces data, and the readable report is built afterwards from the data, which is why the same results can be rendered as a full site or a single-page summary.
Aggregation builds the living documentation
After the tests finish, the aggregate goal of the serenity-maven-plugin, or the aggregate task in Gradle, reads every JSON outcome and generates the HTML report at target/site/serenity/index.html. The Requirements tab is the heart of it. Serenity derives a requirements hierarchy from the folder structure of feature files for Cucumber, or the package structure for JUnit, so a folder per capability containing a feature file per feature becomes a tree of capabilities and features with their scenarios and status. Pending scenarios, written but not yet automated, appear too, which is what lets the report describe what the product should do as well as what passed.
Screenplay: actors, tasks and questions
Screenplay models a test as actors who have abilities, such as browsing the web or calling an API, and who perform tasks made of smaller interactions, then ask questions about the state of the system. An actor attemptsTo open a page, enter a value or add an item, and the report renders those calls almost word for word. Because tasks are small objects composed from interactions rather than methods on a page class, they combine freely and are reused across features without inheritance hierarchies. The cost is more classes and a vocabulary that new team members must learn before they are productive.
Built on JUnit or Cucumber, not instead of them
Serenity is not a test runner. For JUnit tests it plugs in through SerenityJUnit5Extension; for Cucumber it plugs in as a Cucumber plugin, SerenityReporterParallel, configured on a JUnit Platform suite class. Execution, discovery, tags and parallelism therefore follow the underlying framework. Serenity adds the WebDriver lifecycle through @Managed fields or cast members, configuration through serenity.conf, and its reporting. Version alignment follows too: Serenity 5.4.0, released on 13 October 2026, moves its dependency management to Cucumber-JVM 8.0.4, JUnit 6.1.3 and Selenium 4.51.0.
Strengths
What it does well
Requirements-based reporting
The Requirements tab presents results as a hierarchy of capabilities, features and scenarios derived from your folders or packages, with coverage and status at each level. A product owner can see which features are implemented, failing or still pending without reading test code, which is the difference between a test report and documentation of the product.
Step-level evidence in reports
Each test shows its steps with parameters, durations, screenshots and, for REST Assured calls, the request and response. For an investigating engineer this often removes the need to rerun a failing test locally, and for audited work it provides evidence of what was actually exercised.
The Screenplay pattern
Actors, abilities, tasks, interactions and questions give a structured way to compose tests from small reusable parts. Built-in interactions such as Open, Enter and Click, questions such as Text.ofEach, and the Ensure assertion library cover common web work, and the same model applies to REST and mobile, so one vocabulary spans the test estate.
Managed WebDriver and configuration
A @Managed WebDriver field or a @CastMember actor gets a browser that Serenity creates, configures and closes, downloading the driver binaries itself. Browser choice, headless mode, capabilities and screenshot policy live in serenity.conf, a HOCON file, so environment differences are configuration rather than code.
Cucumber integration
With the SerenityReporterParallel plugin, Cucumber scenarios appear in the Serenity report with their Gherkin text, steps and screenshots. Step definitions can take an Actor directly through a custom parameter type, so a step such as {actor} adds {string} to the list hands the named actor to Screenplay tasks without extra wiring.
API and mobile in the same model
serenity-rest-assured and the Screenplay REST module record API calls into the report and let an actor call an API as an ability. Appium integration does the same for mobile. Mixed journeys, such as creating data through the API and checking it in the browser, read as one coherent test.
Pricing
Serenity BDD pricing and licensing
Serenity BDD is free and open source under the Apache 2.0 licence, distributed through Maven Central, with no paid edition or locked features. The project offers commercial support packages through Serenity Dojo, and its README states that almost all current development is driven by commercial support contracts. The other costs are the usual ones: CI time, browsers or a grid, and the engineering time to learn Screenplay and maintain the suite.
- Licence: Apache 2.0, declared in the Serenity POMs on Maven Central.
- No tiers: reporting, Screenplay and every integration module are in the open source libraries.
- Commercial support: paid support packages are offered through Serenity Dojo; the project says unfunded issues get little bandwidth.
- Hidden cost: learning time. Screenplay and Serenity’s conventions take weeks to use well, and mixed styles are costly to maintain.
- Hidden cost: upgrades. Serenity 5 requires Java 17, and 4.0 moved annotations to new packages, so majors need planned migration work.
Checked against the vendor’s own pages on 13 October 2026. Pricing changes; confirm on the official site before buying.
Getting started
Serenity BDD tutorial: getting started
Setup, step by step
- Install a JDK, version 17 or later, and Maven.
- Create a repository from the serenity-junit-screenplay-starter or serenity-cucumber-starter template on GitHub.
- Set serenity.test.root and the browser options in src/test/resources/serenity.conf.
- Write a JUnit 5 test with @ExtendWith(SerenityJUnit5Extension.class) and a @CastMember actor.
- Run mvn clean verify, which runs the tests and then aggregates the report.
- Open target/site/serenity/index.html and read the test in the Test Results and Requirements tabs.
Install
git clone https://github.com/serenity-bdd/serenity-junit-screenplay-starter.git
cd serenity-junit-screenplay-starter
# verify, not test: the report is aggregated after the integration-test phase
mvn clean verifyA first example
package todomvc.features;
import net.serenitybdd.junit5.SerenityJUnit5Extension;
import net.serenitybdd.screenplay.Actor;
import net.serenitybdd.screenplay.actions.Enter;
import net.serenitybdd.screenplay.actions.Open;
import net.serenitybdd.screenplay.annotations.CastMember;
import net.serenitybdd.screenplay.questions.Text;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.openqa.selenium.Keys;
import static org.assertj.core.api.Assertions.assertThat;
// Without this extension the test runs, but Serenity records nothing
@ExtendWith(SerenityJUnit5Extension.class)
class AddNewTodos {
// An actor with a browser that Serenity opens and closes
@CastMember(name = "Toby")
Actor toby;
@Test
@DisplayName("Add a todo item to an empty list")
void addToEmptyList() {
toby.attemptsTo(
Open.url("https://todomvc.com/examples/angularjs/#/"),
Enter.theValue("Buy some milk").into(".new-todo").thenHit(Keys.RETURN)
);
// Questions read the state of the page; the actor asks them
var todos = toby.asksFor(Text.ofEach(".todo-list li"));
assertThat(todos).containsExactly("Buy some milk");
}
}What trips people up first
Running the tests and finding no Serenity report, or no tests at all. The starter projects run tests with the Failsafe plugin in the integration-test phase and skip Surefire, then build the report in post-integration-test with the aggregate goal, so mvn test does nothing useful: run mvn clean verify. The second trap is the test itself. Serenity’s own tutorial warns that a JUnit 5 test needs @ExtendWith(SerenityJUnit5Extension.class) and the org.junit.jupiter.api.Test annotation; with the JUnit 4 @Test, or without the extension, the test either does not run or runs without Serenity recording it. Older tutorials also import annotations from net.thucydides packages, which moved in Serenity 4.
In practice
Using Serenity BDD in practice
Laying out requirements so the report makes sense
Design the folder structure first, because it becomes the report. For Cucumber, put feature files under src/test/resources/features in a folder per capability, for example features/checkout and features/loyalty, with one feature file per feature; Serenity turns that tree into the Requirements tab. For JUnit, the package structure plays the same role, rooted at the package named by serenity.test.root. Keep the depth consistent across branches, since the documentation notes that uneven depths confuse the hierarchy. Keep Screenplay classes, tasks, questions and targets in their own package, separate from tests, because they are reused across many features. Hold browser and environment settings in serenity.conf rather than in code.
# src/test/resources/serenity.conf
serenity {
# Package whose sub-packages become requirements in JUnit reports
test.root = todomvc.features
# Screenshots only on failure keep reports small and runs fast
take.screenshots = FOR_FAILURES
}
headless.mode = true
webdriver {
driver = chrome
capabilities {
browserName = "chrome"
"goog:chromeOptions" {
args = ["--window-size=1280,900", "no-sandbox", "disable-dev-shm-usage"]
}
}
}Screenplay with Cucumber step definitions
With Cucumber, the pattern is a thin step definition that hands work to an actor. A custom parameter type turns a name in the step text into an actor from the stage, so a step such as {actor} adds {string} to the list receives Toby or Rama directly. A @Before hook sets the stage with an OnlineCast, which gives each actor a browser. Tasks are built with Task.where, which takes a description that appears in the report and the interactions it performs. Keep tasks small and named in business terms; a task that needs a long description is usually two tasks.
// Turns "Toby" in step text into an Actor with a browser
public class ParameterDefinitions {
@ParameterType(".*")
public Actor actor(String actorName) {
return OnStage.theActorCalled(actorName);
}
@Before
public void setTheStage() {
OnStage.setTheStage(new OnlineCast());
}
}
// A reusable task; the description appears in the report
public class AddAnItem {
public static Performable withName(String itemName) {
return Task.where("{0} adds an item called " + itemName,
Enter.theValue(itemName)
.into(TodoListPage.ITEM_NAME_FIELD)
.thenHit(Keys.ENTER));
}
}
public class AddItemStepDefinitions {
@When("{actor} adds {string} to the list")
public void addsToTheList(Actor actor, String itemName) {
actor.attemptsTo(AddAnItem.withName(itemName));
}
@Then("{actor} sees {string} as an item in the TODO list")
public void seesItem(Actor actor, String expected) {
actor.attemptsTo(Ensure.that(TodoListPage.ITEMS_LIST).hasText(expected));
}
}Running in GitHub Actions and publishing the report
The pipeline is a Maven build with one difference from a plain JUnit project: the job must run verify so the aggregate goal builds the report, and the report folder should be uploaded even when tests fail, because a failing run is exactly when the report is needed. Run headless in CI through headless.mode in serenity.conf or a system property. The Serenity documentation also shows publishing the report to GitHub Pages for a browsable history of the latest run on main.
# .github/workflows/serenity.yml
name: acceptance
on: [push, pull_request]
jobs:
serenity:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-java@v6
with:
distribution: temurin
java-version: '21'
cache: maven
# verify runs the tests, then aggregates the HTML report
- run: mvn -B clean verify -Dheadless.mode=true
- uses: actions/upload-artifact@v7
if: always()
with:
name: serenity-report
path: target/site/serenity
retention-days: 30Parallel Cucumber scenarios with Serenity
Parallel execution comes from Cucumber on the JUnit Platform, not from Serenity, so it is configured in junit-platform.properties. The suite class must register Serenity’s SerenityReporterParallel plugin so that outcomes from concurrent scenarios are recorded correctly. Each actor in an OnlineCast gets its own browser, so scenarios are isolated as long as test data is unique per scenario. Start with a fixed parallelism that matches the cores and memory of the CI runner, since each thread runs a browser.
// src/test/java/starter/CucumberTestSuite.java
@Suite
@IncludeEngines("cucumber")
@SelectClasspathResource("/features")
@ConfigurationParameter(
key = PLUGIN_PROPERTY_NAME,
value = "net.serenitybdd.cucumber.core.plugin.SerenityReporterParallel,pretty")
public class CucumberTestSuite {}
// src/test/resources/junit-platform.properties
// cucumber.execution.parallel.enabled=true
// cucumber.execution.parallel.config.strategy=fixed
// cucumber.execution.parallel.config.fixed.parallelism=4
// cucumber.execution.parallel.config.fixed.max-pool-size=4Upgrading and keeping a Serenity suite healthy
Serenity 5.0.0, published in December 2025, raised the Java baseline from 11 to 17 and moved to JUnit 6. Serenity 5.4.0, released on 13 October 2026, aligns with Cucumber-JVM 8, so read the Cucumber 8 notes too: Java 17, the JUnit Platform engine instead of the deprecated JUnit 4 and TestNG runners, and an explicit Jackson dependency for some Cucumber report plugins. Projects coming from Serenity 3 also need the 4.0 package changes, such as @Step and @Managed moving to net.serenitybdd.annotations. Day to day, pick one style, Screenplay or action classes, and keep to it; set screenshots to FOR_FAILURES unless an audit needs more; and review the Requirements tab with product owners, which is the point of the tool.
Pitfalls
Common pitfalls
Running mvn test and getting no report
Why it happens: The starter projects run tests with Failsafe in the integration-test phase, skip Surefire, and build the report in post-integration-test with the aggregate goal. mvn test stops before any of that.
The fix: Run mvn clean verify locally and in CI, or call the aggregate goal explicitly after the tests. In Gradle, run the aggregate task after test.
Tests that run but do not appear in the report
Why it happens: A JUnit 5 test without @ExtendWith(SerenityJUnit5Extension.class), or a Cucumber suite without the SerenityReporterParallel plugin, runs normally but Serenity records nothing about it.
The fix: Add the extension to every JUnit test class, or a shared base class, and register the Serenity Cucumber plugin on the suite class.
Copying imports from Serenity 2 and 3 tutorials
Why it happens: Many articles import @Step, @Managed and other annotations from net.thucydides packages. Serenity 4.0 moved them to net.serenitybdd.annotations, and old JUnit 4 runners such as SerenityRunner belong to an older era.
The fix: Use the current starter projects and documentation as the reference, import annotations from net.serenitybdd.annotations, and use the JUnit 5 extension.
Upgrading to Serenity 5 on an older JDK
Why it happens: Serenity 5 is compiled for Java 17, up from Java 11 for the 4.x line, so a build on Java 11 fails as soon as the new version is resolved.
The fix: Move the build and CI images to Java 17 or later first, then upgrade Serenity, and align Cucumber and JUnit versions with the Serenity BOM.
Screenshots on every step slowing runs and bloating reports
Why it happens: Capturing a screenshot for every action is tempting for evidence, but each one costs time and disk, and large suites produce reports that are slow to archive and open.
The fix: Set serenity.take.screenshots to FOR_FAILURES in serenity.conf, and raise it only for suites where the evidence is genuinely required.
Relying on the Jira integration modules
Why it happens: The README marks serenity-jira-plugin and serenity-jira-requirements-provider as deprecated and no longer maintained, citing Atlassian API token restrictions.
The fix: Link scenarios to Jira through tags and your test management tool, such as Xray or Zephyr importing Cucumber results, rather than building on the deprecated modules.
Compared
How Serenity BDD compares
| Tool | What it is | Languages | Licence | Test structure | Report focus |
|---|---|---|---|---|---|
| Serenity BDD | Framework and reporting over JUnit or Cucumber | Java | Apache 2.0 | Screenplay, action classes or page objects | Requirements-based living documentation |
| Cucumber | BDD runner for Gherkin scenarios | Java, JavaScript, Ruby and others | MIT | Gherkin plus step definitions | Single-page HTML, JSON, JUnit XML |
| Allure Report | Reporting tool for many frameworks | Adapters for Java, Python, JavaScript and more | Apache 2.0 | Whatever the underlying framework uses | Results, history, trends and attachments |
| JUnit | Test framework for the JVM | Java, Kotlin, Groovy | EPL 2.0 | Plain test classes and methods | XML results for CI tools |
FAQ
Frequently asked questions
Is Serenity BDD free?
Yes. Serenity BDD is open source under the Apache 2.0 licence and distributed through Maven Central, with no paid edition. The project offers commercial support packages through Serenity Dojo, and its README says almost all current development is driven by those contracts, so fixes that nobody funds may take longer. Your other costs are CI time, browsers or a grid, and the time to learn its conventions.
What is new in Serenity BDD 5?
Serenity 5.0.0, published in December 2025, moved the baseline to Java 17, from Java 11 in the 4.x line, and to JUnit 6. Serenity 5.4.0, released on 13 October 2026, updates its managed versions to Cucumber-JVM 8.0.4, JUnit 6.1.3 and Selenium 4.51.0. Check your Java version first, then follow the Cucumber 8 upgrade notes if you use Cucumber.
Serenity BDD vs Cucumber: do I need both?
They do different jobs. Cucumber runs Gherkin scenarios against step definitions; Serenity sits on top, recording each step with screenshots and building a requirements-based report, and adds the Screenplay pattern and WebDriver management. Many teams use them together. If your scenarios are read only by engineers and the standard Cucumber HTML report is enough, you do not need Serenity; if stakeholders use the results as documentation, Serenity adds a lot.
Is Serenity BDD the same as Serenity/JS?
No. Serenity BDD is the Java library described here. Serenity/JS is a separate JavaScript and TypeScript framework that implements the Screenplay pattern and can produce its reports through the Serenity BDD reporting CLI. They share ideas and a reporting style, but they are different projects with different codebases, documentation and release cycles.
What is the Screenplay pattern?
A way of structuring tests around actors who have abilities, such as browsing the web or calling an API, perform tasks built from smaller interactions, and ask questions about the system’s state. Compared with page objects, it favours small composable objects over large page classes, which makes reuse easier on big suites. It takes longer to learn, and it pays off mainly when several people maintain a large suite over years.
Can Serenity BDD use Playwright instead of Selenium?
Yes. Serenity publishes Playwright modules, serenity-playwright and serenity-screenplay-playwright, alongside its Selenium WebDriver integration, and its documentation has a Playwright section. Selenium remains the most documented path, used by the starter projects and tutorials, so expect fewer examples when you build on the Playwright modules.
Why does my Serenity report not appear after the tests run?
The report is built by the aggregate goal of the Serenity Maven plugin, or the aggregate task in Gradle, after the tests finish. In the starter projects this is bound to the post-integration-test phase, so run mvn clean verify rather than mvn test. Check also that JUnit tests use SerenityJUnit5Extension and that Cucumber suites register the SerenityReporterParallel plugin, otherwise nothing is recorded.
Alternatives
Serenity BDD alternatives worth weighing
Resources
Where to go next
Picking the wrong tool costs more than picking late.
QAble advises on toolchain decisions and then implements them, with engineers who have run these tools on real delivery. Start with a free QA audit.