Parallel Execution
Selenium Boot supports parallel test execution out of the box. Configure the thread count in selenium-boot.yml and the framework handles thread-safe driver management automatically.
Configuration
execution:
mode: local
parallel: methods # none (default) | methods | classes | tests | instances
threadCount: 4 # number of concurrent browser sessions
maxActiveSessions: 4 # semaphore cap on concurrent browsers
browser:
name: chrome
timeouts:
explicit: 10
pageLoad: 30
parallel, threadCount and maxActiveSessions all live under execution: — see the Configuration Reference. timeouts.explicit and timeouts.pageLoad are required by every selenium-boot.yml, parallel or not.
maxActiveSessions acts as a hard ceiling on concurrent browsers. If threadCount is 4 but maxActiveSessions is 2, at most 2 browsers will run at the same time.
TestNG suite file
Parallel execution requires a TestNG suite XML file:
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="SeleniumBoot" parallel="methods" thread-count="4">
<test name="All Tests">
<classes>
<class name="com.example.tests.LoginTest"/>
<class name="com.example.tests.CheckoutTest"/>
<class name="com.example.tests.SearchTest"/>
</classes>
</test>
</suite>
Run it with Maven Surefire:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>testng.xml</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
How thread safety works
| Concern | How Selenium Boot handles it |
|---|---|
| WebDriver instance | ThreadLocal<WebDriver> — each thread has its own driver |
| Config access | AtomicReference — reads are lock-free |
| Step recording | ConcurrentHashMap keyed by test ID |
| Session limiting | Semaphore (fair) — acquired before driver create, released after quit |
| Screenshot capture | Reads driver from ThreadLocal — always the right instance |
You do not need to do anything special in your tests. getDriver() always returns the driver for the calling thread.
Parallel modes
execution.parallel is validated at suite bootstrap, before any test runs, against TestNG's own set of parallel modes. An unrecognised value fails immediately with a message naming both the rejected value and the accepted ones.
| Mode | Description | Recommended |
|---|---|---|
none | Sequential execution (default) | |
methods | Each test method runs in its own thread | Best general choice |
classes | Each test class runs in a thread | Use when tests within a class must be sequential |
tests | Each <test> in the suite XML runs in a thread | Use to isolate suite-level groupings |
instances | Each test class instance runs in a thread | Rarely needed — factory-driven suites |
Parallel + per-suite lifecycle
When browser.lifecycle: per-suite is combined with parallel execution, each thread opens its own browser once and reuses it for all tests on that thread.
Thread 1: Chrome opens → Test A → Test B → Test C → Chrome closes
Thread 2: Chrome opens → Test D → Test E → Test F → Chrome closes
maxActiveSessions still limits the total concurrent browsers.
Writing parallel-safe tests
Do not use static mutable state — static fields are shared across threads:
// ❌ not thread-safe
public class LoginTest extends BaseTest {
private static LoginPage loginPage; // shared — threads overwrite each other
@Test
public void login() {
loginPage = new LoginPage(getDriver());
loginPage.login("admin", "secret");
}
}
// ✅ thread-safe — instance field, each thread has its own test instance
public class LoginTest extends BaseTest {
private LoginPage loginPage;
@Test
public void login() {
loginPage = new LoginPage(getDriver());
loginPage.login("admin", "secret");
}
}
TestNG creates a new instance of each test class per thread, so instance fields are safe.
Disabling parallel execution
execution:
parallel: none
Or simply omit execution.parallel — none (sequential execution) is the default.