Skip to main content

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

selenium-boot.yml
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:

testng.xml
<!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:

pom.xml
<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

ConcernHow Selenium Boot handles it
WebDriver instanceThreadLocal<WebDriver> — each thread has its own driver
Config accessAtomicReference — reads are lock-free
Step recordingConcurrentHashMap keyed by test ID
Session limitingSemaphore (fair) — acquired before driver create, released after quit
Screenshot captureReads 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.

ModeDescriptionRecommended
noneSequential execution (default)
methodsEach test method runs in its own threadBest general choice
classesEach test class runs in a threadUse when tests within a class must be sequential
testsEach <test> in the suite XML runs in a threadUse to isolate suite-level groupings
instancesEach test class instance runs in a threadRarely 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.parallelnone (sequential execution) is the default.