Scenario Outline iteration and @Before/@After hook lifecycle
0 reputation · 14 Jul 2021, 02:29 UTC
0 reputation · 14 Jul 2021, 02:29 UTC
Cucumber-JVM utilizes Scenario Outlines to execute a single scenario multiple times based on the rows provided in an Examples table. Each row is treated as an independent scenario for the purpose of reporting and execution.
When integrating Cucumber with external test runners like JUnit or TestNG, the lifecycle of @Before and @After hooks must align with each iteration of the Examples table to ensure test isolation. However, the precise interaction between these hooks and the iteration cycle can vary depending on the runner configuration.
What is the guaranteed execution order of hooks when a Scenario Outline is processed across multiple rows? Does the framework ensure a clean state by triggering the full hook lifecycle for every individual row in the Examples table regardless of the runner used?
34775 reputation · 14 Jul 2021, 10:39 UTC
In Cucumber‑JVM the parser expands a Scenario Outline into one scenario instance per row in the Examples table. Each instance is reported separately and is treated as a normal scenario for the purposes of hook execution.
@Before that match the scenario’s tags are executed in the order they appear in the code (or in the numeric @order if supplied).@After hooks run in reverse declaration order.Tag filtering is evaluated for each instance, so a hook that applies to @smoke will run only for rows whose example row tags include @smoke.
Whether the test is launched via JUnit (4, 5) or TestNG, the per‑instance hook sequence is identical. The only difference is that class‑level runner hooks (@BeforeAll, @AfterAll, @BeforeClass, @AfterClass) execute once per test class, not per example row.
Feature: Login
@smoke
Scenario Outline: Successful login
Given I open the login page
When I login as <user> with <password>
Then I should see <welcome>
Examples:
| user | password | welcome |
| alice | secret1 | Alice's Dashboard |
| bob | secret2 | Bob's Dashboard |
public class Hooks {
@Before(order = 1)
public void beforeScenario(Scenario scenario) {
System.out.println("Before: " + scenario.getName());
}
@After(order = 1)
public void afterScenario(Scenario scenario) {
System.out.println("After: " + scenario.getName());
}
}
Running this feature with either runner will print:
Before: Successful login (alice)
After: Successful login (alice)
Before: Successful login (bob)
After: Successful login (bob)
Yes – Cucumber‑JVM guarantees a clean state for each Examples row by invoking the full @Before / @After lifecycle for every row, regardless of the underlying test runner. The only hooks that are not repeated per row are the class‑level lifecycle hooks provided by the runner itself.
If you observe that hooks are not run per row, confirm that you are using a modern Cucumber‑JVM version (≥ 7). Older releases had different integration behavior.
Use comments to ask for clarification. Post a solution as an answer.
34,775 reputation · 14 Jul 2021, 05:32 UTC
To clarify the lifecycle: Cucumber-JVM treats every row in an Examples table as a standalone scenario. Consequently, the @Before and @After hooks are guaranteed to execute for every individual row, regardless of whether you are using JUnit or TestNG. The sequence is strictly @Before → Steps → @After for each iteration.
However, it is important to distinguish these from suite-level hooks. If you are using @BeforeAll or @AfterAll (available in newer versions), these trigger only once per test suite execution, not per row. Additionally, while the hook lifecycle resets, any state stored in static variables will persist across iterations. To verify isolation, you can implement a @Before hook that logs a unique identifier or increments a counter to confirm it triggers exactly once per example row.