What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Acceptance tests are most useful when they describe system behavior in a way that developers, testers, and product stakeholders can all understand. JGiven brings that clarity to Java by letting teams write executable scenarios in a fluent Given-When-Then style while still using familiar test tools and ordinary Java code.
With JGiven, acceptance tests are organized around scenario stages that separate setup, action, and verification steps. This structure encourages readable test design, reusable domain-specific steps, meaningful assertions, and reports that show what the system does rather than how the test is implemented.
As an Amazon Associate I earn from qualifying purchases.
What JGiven Is and When to Use It
JGiven is a Java testing library for writing acceptance tests in a behavior-driven style without moving test scenarios into separate text files. Instead of using external Gherkin feature files, JGiven lets developers describe behavior directly in Java using fluent stage methods such as given(), when(), and then(). A test reads like a scenario, while still being compiled, refactored, and executed as normal Java code.
The central idea is to separate the story of a test from the mechanics that make it pass. A JGiven test class usually coordinates three kinds of stages: a Given stage that prepares data and system state, a When stage that performs the action under test, and a Then stage that verifies the observable result. Each stage is a regular Java class with methods named in a readable way, such as a_customer_exists(), the_customer_places_an_order(), or the_order_is_confirmed(). JGiven converts these method calls into structured reports, replacing underscores with spaces and showing parameters as part of the scenario text.
#1 Best Overall
JGiven is most useful when tests need to communicate behavior to more than just the person who wrote them. It works well for acceptance tests around APIs, service workflows, domain rules, business processes, and user-facing behavior where the sequence of setup, action, and result matters. For example, an order management service can be tested with scenarios such as “given a customer with store credit, when the customer buys an item, then the remaining credit is reduced.” The test remains executable Java, but the generated report can be read by developers, testers, product owners, and support engineers.
It is also a strong fit for teams that want behavior-driven development practices but prefer not to maintain a separate step-definition layer. Tools based on plain-text scenarios can be valuable, especially when non-developers actively write scenarios. JGiven takes a different approach: scenarios live in the test source set, so IDE navigation, autocomplete, static typing, renaming, and compile-time failures all work naturally. This makes it especially convenient for Java teams that own both the implementation and the acceptance test suite.
Good use cases for JGiven
- Service-level acceptance tests: verifying complete behavior across application services, repositories, message handlers, or REST endpoints.
- Domain workflow tests: describing business processes such as checkout, onboarding, invoicing, cancellation, or approval flows.
- Regression suites: capturing previously broken behavior in a readable format that remains easy to extend.
- Executable documentation: producing reports that explain what the system does, using examples that are run during the build.
- Team-shared test language: building reusable stage methods that express common business concepts consistently.
JGiven is not intended to replace every kind of Java test. Low-level unit tests for small algorithms, simple getters, validation helpers, or isolated utility classes are often clearer with plain JUnit and an assertion library. JGiven adds the most value when a test benefits from a narrative structure and when the generated report helps readers understand the behavior being protected.
A practical rule is to use JGiven when the test name alone is not enough to explain the behavior. If the scenario has meaningful preconditions, an action that represents user or system behavior, and outcomes that matter at the acceptance level, JGiven can make the test easier to read and maintain. If the test only checks a single method return value with minimal setup, a conventional unit test is usually simpler.
Adding JGiven to a Java Test Project
JGiven is usually added as a test-scoped dependency alongside the test framework already used by the project. Most teams use it with JUnit 5 or JUnit 4, although TestNG is also supported. The core idea is that JGiven supplies the scenario infrastructure and report generation, while the underlying test framework still discovers and runs the tests during the normal build.
Maven setup
For a Maven project using JUnit 5, add the JGiven JUnit 5 module and the JUnit Jupiter engine to the test dependencies. Keep JGiven scoped to test so it is not packaged with production code.
<dependencies>
<dependency>
<groupId>com.tngtech.jgiven</groupId>
<artifactId>jgiven-junit5</artifactId>
<version>1.3.1</version>
<scope>test</scope>
</dependency>
Free tools Windows power users keep installed
One-click scans. No signup required.
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
</dependencies>
If the project still runs JUnit 4 tests, use the JUnit 4 integration instead:
<dependency>
<groupId>com.tngtech.jgiven</groupId>
<artifactId>jgiven-junit</artifactId>
<version>1.3.1</version>
<scope>test</scope>
</dependency>
Gradle setup
In a Gradle build using JUnit 5, declare JGiven in the testImplementation configuration and enable the JUnit Platform. This lets JGiven tests run with the same gradle test task as unit and integration tests.
dependencies {
testImplementation "com.tngtech.jgiven:jgiven-junit5:1.3.1"
testImplementation "org.junit.jupiter:junit-jupiter:5.10.2"
}
test {
useJUnitPlatform()
}
For JUnit 4 projects, replace the JUnit 5 artifact with jgiven-junit and keep the existing JUnit 4 runner configuration. A mixed codebase can contain both styles during migration, but each test class should use one integration style consistently.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallProject structure
A common layout is to keep acceptance tests under src/test/java when they are fast and self-contained. If they start external services, browsers, containers, or a deployed application, it is often cleaner to place them under a separate source set such as src/acceptanceTest/java or src/integrationTest/java. That separation makes it easier to run quick unit tests on every commit and execute acceptance tests in a dedicated build stage.
Rank #2
- Test classes describe business scenarios, for example
CheckoutAcceptanceTest. - Stage classes hold reusable Given, When, and Then steps, for example
CustomerStage,CartStage, andOrderStage. - Fixtures and test data builders create domain objects without filling the scenario text with setup details.
- Adapters call APIs, repositories, message queues, or UI drivers used by the acceptance tests.
Basic test class configuration
With JUnit 5, a JGiven test class typically extends ScenarioTest with three stage type parameters. These parameters represent the Given, When, and Then parts of the scenario. The test method itself remains short and reads like a specification.
class CheckoutAcceptanceTest
extends ScenarioTest<GivenCustomer, WhenCheckout, ThenOrder> {
@Test
void registered_customer_can_place_an_order() {
given().a_registered_customer()
.and().a_cart_with_items();
when().the_customer_checks_out();
then().an_order_is_created()
.and().a_confirmation_email_is_sent();
}
}
Once the dependency and runner setup are in place, run the normal test command: mvn test or gradle test. JGiven will execute with the test framework and collect structured scenario data for reporting. From there, the next step is to design expressive stages that hide technical details while keeping each acceptance test readable to developers, testers, and product stakeholders.
Writing Given-When-Then Acceptance Tests
JGiven acceptance tests are written around the familiar Given-When-Then structure: set up the context, perform the action, and verify the observable result. In Java, this structure is expressed through fluent stage methods rather than long test method bodies. A test reads like a short scenario, while the implementation details live in dedicated stage classes.
A typical JGiven test method describes one business behavior from the user’s point of view. For example, an online shop scenario might state that a customer with an empty basket adds a product and then sees that product in the basket . The test should avoid low-level details such as repository calls, mock configuration, or HTTP client setup in the scenario itself. Those details belong behind stage methods such as a_customer_with_an_empty_basket(), the_customer_adds_a_product(), and the_basket_contains_the_product().
Structuring a Scenario
In a JGiven test, the scenario method usually calls given(), when(), and then() methods provided by the JGiven test base class or rule. Each call returns a stage object, allowing method chaining and natural-language naming. The resulting test should be understandable even to someone who does not know the internals of the application.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →- Given methods prepare state, input data, authenticated users, fixtures, or external service responses.
- When methods execute the behavior being tested, such as submitting a form, calling an API, or processing a message.
- Then methods assert the outcome, including returned data, persisted state, emitted events, or visible UI changes.
For example, a readable scenario can be shaped as a sequence: given().a_registered_customer(), and().a_product_is_available(), when().the_customer_places_an_order(), and then().an_order_confirmation_is_shown(). The and() method is useful when several conditions or expectations belong to the same phase. It keeps the scenario expressive without forcing every line to repeat given() or then().
Designing Test Steps
Stage method names should describe behavior, not implementation. Prefer the_invoice_is_sent_to_the_customer() over smtp_server_receives_message() unless the SMTP interaction is the actual acceptance criterion. This keeps tests stable when internal implementation changes. Parameters can make steps reusable: a_customer_named("Alice"), a_product_costing(1999, "EUR"), or the_order_total_is(1999, "EUR"). JGiven includes parameter values in the generated scenario report, so concrete examples become part of the documentation.
Assertions usually belong in Then stages. You can use AssertJ, Hamcrest, JUnit assertions, or another assertion library. Keep assertions close to the language of the behavior: check that an order is confirmed, a validation message is returned, or an account balance changes as expected. If one scenario needs many unrelated assertions, consider splitting it into smaller acceptance tests that each describe one outcome.
Good acceptance scenarios are specific but not brittle. They use real business terms, meaningful example data, and clear outcomes. They avoid excessive setup, hidden side effects, and generic step names such as execute() or check_result(). When written this way, JGiven tests serve both as automated verification and as living documentation of how the system is expected to behave.
Rank #3
Creating and Reusing Stage Classes
JGiven stage classes are the main building blocks behind readable acceptance tests. A stage class groups related step methods, such as preparing test data, executing an action, or checking an outcome. Instead of placing all test behavior in a single test method, you move the details into named methods that read like a scenario: given a registered customer, when the customer places an order, then the order is confirmed.
A typical setup uses separate classes for each part of the flow. For example, GivenCustomerStage can create customers and seed account state, WhenOrderStage can call the application service or REST endpoint, and ThenOrderStage can verify persisted data, response bodies, emitted events, or UI state. This keeps each stage focused and makes scenarios easier to scan. The test class then wires these stages through JGiven annotations such as @ScenarioStage, letting the test method stay short and expressive.
Designing stage methods
Stage methods should describe business behavior rather than low-level implementation. A method named a_customer_with_an_active_subscription() is more useful in an acceptance test than insert_customer_row(). The method may still insert records, call builders, or use repositories internally, but the scenario exposes the language of the domain. This distinction helps product owners, testers, and developers discuss the same behavior without translating database or API details.
- Keep names readable: use method names that form a sentence in the generated report.
- Return the stage type: return
self()or the current stage type so steps can be chained fluently. - Use parameters for variation: prefer
a_customer_with_balance(BigDecimal amount)over several nearly identical methods. - Hide technical setup: builders, repositories, mock servers, and fixtures should stay inside the stage.
Sharing state between stages
Acceptance tests often need state created in one step and used later. JGiven stages can keep fields such as a customer id, an HTTP response, a command result, or a domain object. When several stage classes need access to the same value, place shared context in a small helper object and inject or pass it into the stages through your test framework setup. This avoids long parameter lists and prevents stages from reaching into each other’s internals.
For example, an order scenario may store the created customer, selected products, submitted request, and response in an OrderScenarioContext. The given stage fills the customer and catalog data, the when stage sends the request and stores the response, and the then stage performs assertions against both the response and the database. The scenario remains clean, while the shared context makes data flow explicit enough to maintain.
Reusing stages across scenarios
Reusable stages are most valuable when they represent stable domain concepts. A GivenUserStage can be reused across login, checkout, profile, and notification scenarios if it only prepares user-related state. Avoid creating one large stage with every possible step in the system. Large stages tend to accumulate unrelated helpers, duplicated setup paths, and ambiguous method names. Smaller stages are easier to compose and safer to change.
It is also helpful to separate acceptance-level stages from lower-level test utilities. A stage method can call an object mother, test data builder, fake payment gateway, or database fixture, but those utilities should not become part of the scenario language. This keeps the public step vocabulary stable even when the internal setup changes. Over time, this separation makes reports more consistent and helps prevent brittle tests tied to technical details.
- Group stages by domain area: customers, orders, payments, inventory, or accounts.
- Prefer composition: let stages use helper classes instead of inheriting large base stages.
- Keep assertions in then stages: avoid mixing verification into setup or action steps.
- Review report output: adjust step names until the generated scenario reads naturally.
Running JGiven Tests with JUnit
JGiven fits naturally into Java projects that already use JUnit. The test class still looks and runs like a normal JUnit test, but it extends a JGiven base class so that scenario stages can be injected and recorded. This means developers can run acceptance tests from an IDE, Maven, Gradle, or a CI pipeline without introducing a separate test runner for day-to-day execution.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problemsUsing JGiven with JUnit 5
For JUnit 5, the common approach is to extend ScenarioTest from the JGiven JUnit 5 integration and provide the stage classes as generic parameters. JGiven then creates the given, when, and then stage instances for each scenario. A typical acceptance test keeps the method name business-focused and delegates the detailed steps to stage methods.
import com.tngtech.jgiven.junit5.ScenarioTest;
import org.junit.jupiter.api.Test;
class CheckoutAcceptanceTest
extends ScenarioTest<CustomerGivenStage, CheckoutWhenStage, CheckoutThenStage> {
Rank #4
@Test
void customer_can_complete_checkout_with_a_valid_card() {
given().a_customer_with_items_in_the_cart()
.and().a_valid_payment_card();
Recommended Free Tools
when().the_customer_checks_out();
then().the_order_is_created()
.and().a_payment_receipt_is_shown();
}
}
This test can be executed with the standard JUnit Platform. In Maven, it is usually picked up by Surefire if it follows naming conventions such as *Test, or by Failsafe if acceptance tests are separated as *IT. In Gradle, it runs through the normal test task unless a dedicated source set or integration-test task is configured.
Using JGiven with JUnit 4
Projects still on JUnit 4 can use the JGiven JUnit 4 integration in a similar way. The test extends the JGiven JUnit 4 ScenarioTest base class and uses @Test from org.junit.Test. The structure of the scenario remains the same, which makes migration from JUnit 4 to JUnit 5 mostly a matter of dependency and annotation changes.
import com.tngtech.jgiven.junit.ScenarioTest;
import org.junit.Test;
public class CheckoutAcceptanceTest
extends ScenarioTest<CustomerGivenStage, CheckoutWhenStage, CheckoutThenStage> {
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers → @Test
public void customer_can_complete_checkout_with_a_valid_card() {
given().a_customer_with_items_in_the_cart();
when().the_customer_checks_out();
then().the_order_is_created();
}
}
Assertions should usually live in the then stage rather than directly in the test method. This keeps the scenario readable while allowing the stage to use AssertJ, Hamcrest, JUnit assertions, or project-specific assertion helpers. For example, then().the_order_is_created() might verify the HTTP response, inspect a database record, and assert that an event was published, while the test method stays focused on behavior.
Practical execution patterns
- Keep fast acceptance tests in the default test task: scenarios that use in-memory components or mocked external systems can run with unit tests.
- Separate slower scenarios: tests that start containers, call real services, or require a full application context are often better named
*ITand run in a dedicated CI stage. - Use normal JUnit lifecycle hooks:
@BeforeEach,@AfterEach,@Before, and@Aftercan prepare shared fixtures, although most business setup should remain in Given stages. - Fail through assertions, not logging: a JGiven scenario is most useful when failures point to a specific Then step with a clear assertion message.
Because JGiven tests are JUnit tests, they also work with common build features such as filtering by class or method name, tagging, parallel execution, and CI test result publishing. The JGiven layer adds readable scenario recording on top of that familiar execution model, so teams get acceptance-test documentation without giving up the tooling they already use.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Generating and Reading JGiven Reports
JGiven’s reports are one of the main benefits of writing acceptance tests with a structured given-when-then style. After a test run, JGiven can turn executed scenarios into readable HTML pages that describe behavior in business-oriented language while still being backed by Java test code. This makes the output useful for developers, testers, product owners, and anyone reviewing whether a feature behaves as expected.
During test execution, JGiven writes intermediate report data, usually as JSON files, under the build directory. The exact location depends on the build tool and test setup, but common paths are similar to target/jgiven-reports/json for Maven projects and build/jgiven-reports/json for Gradle projects. These files are then converted into an HTML report by the JGiven report generator. In many projects, this is wired into the Maven or Gradle build so the report is produced as part of the verification phase or after the test task finishes.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Generating HTML Reports
With Maven, teams commonly configure the JGiven Maven plugin so reports are generated after tests run. The usual flow is to execute the acceptance test suite first, then invoke the report goal as part of the build lifecycle. With Gradle, the JGiven plugin can be configured to read the generated JSON data and create the HTML output under the build reports directory. Once generated, open the report’s index.html file in a browser to inspect scenarios, steps, tags, durations, and failures.
- Run the acceptance tests: execute the JUnit-based JGiven tests through Maven, Gradle, or the IDE.
- Collect report data: allow JGiven to write its JSON files during the test run.
- Generate the HTML report: use the configured Maven or Gradle reporting task.
- Publish the report: attach it to CI build artifacts so the whole team can review it.
Reading Scenario Output
A JGiven report is organized around test classes and scenarios. Each scenario shows the rendered steps in the same order they were called in the test method. For example, a Java call such as given().a_registered_customer() appears as a readable step like “Given a registered customer”. This translation from method names to plain text is what makes the report approachable without duplicating test documentation in a separate file.
Best Value
Failures are shown next to the step where the assertion or action failed, along with the stack trace and error message. This helps narrow the investigation to the behavior being exercised rather than forcing readers to search through raw test logs. If stage methods include parameters, those values can appear in the report as well, making scenarios more concrete: “When the customer orders 3 items” is more useful than a generic “When the customer places an order”.
| Report Element | How to Use It |
|---|---|
| Scenario title | Check that it describes a user-visible behavior rather than an implementation detail. |
| Step list | Read it as a short executable specification of the feature. |
| Parameters | Confirm that data values make the example specific and easy to discuss. |
| Failure location | Use the failed step and stack trace to identify the broken behavior or incorrect expectation. |
For maintainable reporting, keep stage method names expressive and avoid overly technical phrasing in steps that appear in the report. Prefer “the payment is declined” over “the payment service returns status code 402” unless the status code is part of the accepted behavior. Add tags for features, epics, or issue identifiers when they help navigation in larger suites. In CI, publish the HTML report for every acceptance test run, even when tests fail, so reviewers can inspect both successful scenarios and broken behavior from the same build output.
Best Practices for Maintainable Acceptance Tests
Maintainable JGiven tests read like product behavior, not like implementation scripts. A scenario should describe what a user or external system does and what observable result follows. Keep the method name, stage method names, and assertions aligned around the same business rule. For example, prefer a scenario such as customer_can_checkout_with_a_valid_credit_card over one that mentions controller methods, database tables, or service internals. This keeps the acceptance suite stable when the code is refactored but the behavior stays the same.
Keep stages focused and reusable
Stage classes work best when each one has a clear role. A Given stage should prepare state, a When stage should perform the action under test, and a Then stage should verify outcomes. Avoid placing assertions in setup methods or performing new actions in verification methods, because that makes failed scenarios harder to diagnose. If a stage method needs many parameters, introduce a small fixture object, builder, or domain-specific helper so the scenario remains readable.
- Use domain language: name methods after business concepts, such as a_registered_customer or the_order_is_submitted.
- Hide technical setup: put HTTP client configuration, test data creation, and database cleanup inside stage helpers.
- Return the stage type: keep fluent chaining consistent by returning self() from stage methods.
- Share state deliberately: use JGiven fields for scenario state, but avoid large mutable objects shared across unrelated steps.
Design assertions around visible behavior
Acceptance tests should assert outcomes that matter to the user, API consumer, or business process. For a REST endpoint, assert status codes, response payloads, emitted events, and persisted state that represents a completed operation. For a UI flow, assert rendered messages, navigation, and final state rather than internal component calls. Use AssertJ, Hamcrest, JUnit assertions, or your project’s preferred library inside Then stages, but keep failure messages precise. A failed assertion such as expected order status to be PAID after successful checkout is more useful than a generic equality failure.
Control test data and execution cost
Acceptance suites can become slow when every scenario starts a full application, creates large datasets, or depends on external services. Use lightweight defaults and create only the records required for the scenario. For Spring Boot tests, reuse application contexts where possible and isolate state with transactions, cleanup routines, or disposable containers. Replace unstable third-party services with test doubles or local contract stubs, while keeping at least a small number of end-to-end checks for critical integrations.
| Practice | Benefit |
|---|---|
| One behavior per scenario | Failures point to a single broken requirement |
| Business-focused step names | Reports are readable by developers, testers, and product owners |
| Reusable stage classes | Common setup and actions stay consistent across the suite |
| Deterministic fixtures | Tests pass or fail for product behavior, not random environment state |
Review JGiven reports as part of test maintenance. If a report reads like a technical trace, rename steps and split overloaded stages. If many scenarios fail after a small product change, the tests may be coupled too tightly to implementation details. Treat the acceptance suite as living documentation: keep it concise, remove duplicate scenarios, and update wording when the product language changes.
Frequently Asked Questions
How is JGiven different from Cucumber for Java acceptance tests?
JGiven keeps scenarios in Java code instead of separate Gherkin feature files, so developers get type safety, refactoring support, and IDE navigation. It is a good fit when the main audience for the tests is the development team, while Cucumber can be better when non-technical stakeholders actively write or review feature files.
Can I use JGiven with JUnit 5?
Yes, JGiven supports JUnit 5 through its Jupiter integration. You typically add the JGiven JUnit 5 dependency, extend the JGiven scenario test base class or use the appropriate extension, and then write test methods that call your given, when, and then stages.
Where should assertions go in a JGiven test?
Assertions usually belong in the “then” stage because that stage describes the expected outcome of the behavior. Keep setup in “given” methods and actions in “when” methods so the scenario reads clearly and failures point to the expected result being checked.
Free tools Windows power users keep installed
One-click scans. No signup required.
How should I organize reusable JGiven stage classes?
Create stage classes around business concepts or application areas, such as user registration, checkout, or account management, instead of making one large shared stage class. Reuse common setup carefully, keep stage methods focused, and avoid hiding too much detail behind vague method names.
Do JGiven reports work in CI pipelines?
Yes, JGiven can generate HTML reports from test execution data, and those reports can be published as build artifacts in tools like Jenkins, GitHub Actions, GitLab CI, or TeamCity. In a CI setup, make sure the report generation step runs after the test phase and that the generated report directory is archived for later review.
Bottom Line
JGiven helps turn Java acceptance tests into readable, behavior-focused scenarios by separating setup, actions, and outcomes into clear Given-When-Then stages. With the right structure, assertions, and integration with JUnit or TestNG, your tests can double as reliable documentation for how the system should behave.
Start by modeling a few user journeys as JGiven scenarios, keep stage methods expressive and reusable, and review the generated reports with your team. From there, refine your suite around clarity, stable assertions, and maintainable test data so your acceptance tests stay useful as the application evolves.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

