Q15 of 21 · BDD / Cucumber

How do you run Cucumber scenarios in parallel, and what are the key pitfalls?

BDD / CucumberSeniorbddcucumberparallelthread-safetyperformance

Short answer

Short answer: Cucumber supports parallel execution via the parallel plugin (Maven Surefire/Failsafe), JUnit 5 parallel execution config, or native JS worker threads. Pitfalls: shared mutable state, shared test data, and non-thread-safe WebDriver instances.

Detail

Java — Maven Surefire parallel:

<plugin>
  <artifactId>maven-surefire-plugin</artifactId>
  <configuration>
    <parallel>methods</parallel>
    <threadCount>4</threadCount>
  </configuration>
</plugin>

Or use the Cucumber parallel plugin to split by feature or scenario:

@CucumberOptions(plugin = {"parallel"})

JavaScript — @cucumber/cucumber parallel flag:

cucumber-js --parallel 4

Key pitfalls:

1. Shared WebDriver / page instance: Each parallel scenario needs its own driver or browser context. Don't share a driver between threads.

// Thread-local driver (Java)
private static final ThreadLocal<WebDriver> driver = new ThreadLocal<>();

@Before
public void setUp() { driver.set(new ChromeDriver()); }
@After
public void tearDown() { driver.get().quit(); driver.remove(); }

2. Shared test data: If two scenarios use the same user account or the same DB row, they'll interfere. Fix: unique test data per scenario (random or scenario-name-scoped IDs).

3. Shared state in step definition classes: Static fields shared across threads cause race conditions. Use DI (PicoContainer creates a new instance per scenario per thread) or the World object in JS.

4. Report merging: Parallel runs produce multiple JSON/XML reports. Merge them with cucumber-results-aggregator or the Allure framework before publishing.

// EXAMPLE

// Thread-safe driver management for parallel Cucumber
public class DriverManager {
    private static final ThreadLocal<WebDriver> tlDriver = new ThreadLocal<>();

    public static WebDriver getDriver() { return tlDriver.get(); }

    public static void initDriver() {
        tlDriver.set(new ChromeDriver());
    }

    public static void quitDriver() {
        if (tlDriver.get() != null) {
            tlDriver.get().quit();
            tlDriver.remove();
        }
    }
}

// WHAT INTERVIEWERS LOOK FOR

ThreadLocal for driver, unique test data per scenario, DI for step def isolation. Report merging as a practical consideration.