Parallel Testing in TestNG
Parallel Testing refers to running multiple tests or test suites simultaneously rather than sequentially. In TestNG, you can configure parallelism at various levels—suites, tests, classes, methods, even individual data‐driven invocations. This is critical for:
- Speed: fully utilize multi‐core CPUs or distributed grids to cut wall-clock time.
- Scalability: cope with growing test suites without linear increases in execution time.
- Feedback loop: faster tests mean quicker validation of new code, enabling more continuous delivery.
Advantages of Parallel Testing #
- Reduced Execution Time
Tests that once took minutes can complete in seconds by distributing work across threads or machines. - Resource Utilization
Leverage idle CPU cores, memory, or remote nodes in a Selenium Grid/Cloud. - Early Detection of Concurrency Issues
Exercises your application under concurrent load, uncovering thread-safety bugs. - Flexible Scalability
Simply increase thread-count or add more <test> blocks to grow horizontally.
Disadvantages of Parallel Testing #
- Thread-Safety Requirements
Shared resources (e.g., single WebDriver, static data) must be made thread-local or synchronized. - Test Isolation
Tests that modify shared state (DB, filesystem, environment variables) can interfere with each other unless properly isolated. - Complex Debugging
Failures may be intermittent (“heisenbugs”) due to race conditions, making root-cause analysis harder. - Infrastructure Overhead
Requires more machines, browsers, or cores—potentially higher cost.
Where to Apply Parallel Execution in TestNG #
TestNG supports parallelism at four main levels in testng.xml:
- Suites (parallel=”suites”)
- Tests (parallel=”tests”)
- Classes (parallel=”classes”)
- Methods (parallel=”methods”)
Additionally, you can run each instance of a class in parallel (parallel=”instances”), or even run data-driven invocations in parallel via @DataProvider(parallel=true).
Configuring Parallel Execution in testng.xml #
<!DOCTYPE suite SYSTEM “https://testng.org/testng-1.0.dtd”>
<suite name=”ParallelSuite”
parallel=”methods”
thread-count=”5″>
<!– Each @Test method across all classes runs in its own thread –>
<test name=”MyTests”>
<classes>
<class name=”com.example.tests.LoginTest”/>
<class name=”com.example.tests.SearchTest”/>
<class name=”com.example.tests.CheckoutTest”/>
</classes>
</test>
</suite>
- parallel can be “suites”, “tests”, “classes”, “methods”, or “instances”.
- thread-count caps the number of concurrent threads.
Running Test Methods in Parallel with Selenium #
When parallelizing Selenium tests, each thread must have its own WebDriver instance. Use a ThreadLocal<WebDriver>:
public class ParallelSeleniumTests {
private static ThreadLocal<WebDriver> tlDriver = new ThreadLocal<>();
@BeforeMethod
@Parameters(“browser”)
public void setUp(String browser) {
WebDriver driver;
if (browser.equals(“firefox”)) {
driver = new FirefoxDriver();
} else {
driver = new ChromeDriver();
}
tlDriver.set(driver);
}
@Test
public void testHomePage() {
WebDriver driver = tlDriver.get();
driver.get(“https://example.com”);
Assert.assertTrue(driver.getTitle().contains(“Example”));
}
@AfterMethod
public void tearDown() {
tlDriver.get().quit();
tlDriver.remove();
}
}
And in testng.xml:
<suite name=”SuiteParallelTests”
parallel=”methods”
thread-count=”3″>
<test name=”ParallelMethods”>
<parameter name=”browser” value=”chrome”/>
<classes>
<class name=”com.example.tests.ParallelSeleniumTests”/>
</classes>
</test>
</suite>
Introduction to Threads in TestNG #
- TestNG manages a thread pool behind the scenes.
- Each unit of work (suite, test, class, method) is submitted as a task.
- Threads pick tasks from the pool up to thread-count.
- You can monitor thread IDs in logs via Thread.currentThread().getId() to confirm parallel runs.
Performance Comparison: Serialized vs. Parallel #
Execution Mode | Total Methods | Avg. Time/Method | Total Time (serial) | Total Time (parallel, 4 threads) |
---|---|---|---|---|
Serial | 40 | 5s | 200s | N/A |
Parallel | 40 | 5s | N/A | ≈ 50s (ideally 200s/4 threads) |
Note: Overhead from thread startup and resource contention means real-world speedup may be slightly less than linear.
Running Test Classes in Parallel #
<suite name=”ClassParallelSuite”
parallel=”classes”
thread-count=”3″>
<test name=”ClassTests”>
<classes>
<class name=”com.example.tests.LoginTest”/>
<class name=”com.example.tests.OrderTest”/>
<class name=”com.example.tests.ProfileTest”/>
</classes>
</test>
</suite>
Each test class’ methods run on its own thread, but within a class methods run sequentially.
Running Test Suites in Parallel #
<suite name=”SuitesInParallel” parallel=”suites” thread-count=”2″>
<suite-files>
<suite-file path=”suite1.xml”/>
<suite-file path=”suite2.xml”/>
</suite-files>
</suite>
This lets you fire off completely separate suite definitions concurrently—useful for long-running, independent pipelines.
Configuring Test Methods to Run in Parallel #
- In addition to suite-level settings, you can override at the <test> level:
<test name=”MethodParallelTest”
parallel=”methods”
thread-count=”5″>
…
</test>
- Or even on a per-DataProvider basis:
@DataProvider(name=”dp”, parallel=true)
public Object[][] data() { … }
@Test(dataProvider=”dp”)
public void dpTest(String input) { … }
With parallel=true, each data row runs in its own thread—ideal for massive data-driven tests.
By strategically applying parallel execution at the right levels—and ensuring thread safety in your Selenium setup—you can dramatically accelerate your TestNG suites and deliver faster, more reliable feedback in your CI/CD pipelines.