Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To run Selenium tests in parallel with TestNG, set a parallel mode and thread-count on the suite in testng.xml, give each concurrent test its own WebDriver session, and keep its data and mutable state isolated. Start with a modest thread count, check how your machine or Selenium Grid handles the load, then increase concurrency gradually. Use parallel="methods" only when individual methods are safe to run independently; otherwise, group work with classes, tests, or instances.

Choose a TestNG parallel mode

TestNG’s suite-level parallel attribute determines what it schedules together. Its thread-count sets the number of threads allocated for parallel execution. Neither setting creates browser capacity by itself: the test processes and available machines still need to support the sessions they request. See the TestNG documentation for the mode definitions and configuration details.

Mode What TestNG groups together Use it when Trade-off
methods Test methods may run concurrently, including methods in the same class. Methods are independent and method-level concurrency is useful. Class fields, browser sessions, and test data need especially careful isolation.
classes Methods in a class stay on the same thread; separate classes can run in parallel. Classes are independent, but methods in a class share setup or state. Parallelism is bounded by the number of runnable classes.
tests Methods within each XML <test> group run on that group’s thread. XML groups represent separate contexts, such as distinct browser parameters. Groups must not collide through shared accounts, records, or other state.
instances Methods on one object instance stay together; separate instances can be run concurrently. Each instance represents a separate, independent test context. Instances must not share mutable resources that cause interference.

When uncertain, choose the narrowest mode that fits the suite’s existing state and fixture assumptions. For example, a suite whose methods rely on fields changed by other methods is not automatically safe under methods just because TestNG can schedule it that way.

Configure the suite in testng.xml

This example runs methods from two test classes with up to four TestNG worker threads:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Parallel Suite" parallel="methods" thread-count="4">
  <test name="UI tests">
    <classes>
      <class name="tests.LoginTest"/>
      <class name="tests.CheckoutTest"/>
    </classes>
  </test>
</suite>

Place the file where your project’s TestNG runner is configured to find it, and use its actual package and class names. To preserve method grouping within classes, change the suite mode to classes. To schedule distinct XML groups, use tests and define multiple <test> elements. Use instances when the test instances are separate contexts. Keep thread-count conservative at first; it is a concurrency setting, not a promise that every requested browser can start immediately.

Give each concurrent test its own browser session

A WebDriver session is mutable: concurrent tests should not issue commands through the same driver object. One straightforward Java pattern is a per-thread driver holder. The following example creates a browser before each test method and quits it after that method, including when the test fails.

package tests;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

public class LoginTest {
    private static final ThreadLocal<WebDriver> DRIVER = new ThreadLocal<>();

    @BeforeMethod
    public void startBrowser() {
        DRIVER.set(new ChromeDriver());
    }

    @Test
    public void loginPageLoads() {
        WebDriver driver = DRIVER.get();
        if (driver == null) {
            throw new IllegalStateException("WebDriver was not initialized");
        }
        driver.get("https://example.com/");
        // Add assertions for the application under test.
    }

    @AfterMethod(alwaysRun = true)
    public void stopBrowser() {
        WebDriver driver = DRIVER.get();
        try {
            if (driver != null) {
                driver.quit();
            }
        } finally {
            DRIVER.remove();
        }
    }
}

This is an implementation choice, not a Selenium requirement. It assumes the setup, test, and teardown for a method run on the same TestNG worker thread, which is the usual lifecycle for this pattern. A framework can instead pass isolated driver instances through its own test context. Whatever design you use, create and tear down each session in a lifecycle that guarantees cleanup; quit() ends the session, while removing a thread-local reference avoids leaving stale state attached to a reused worker thread.

Creating a local Chrome session also requires a compatible browser and driver setup in the environment running the tests. If you need remote browsers, use Selenium Grid and a RemoteWebDriver instead of constructing a local ChromeDriver.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Keep test state independent

Separate drivers do not prevent tests from interfering through application data or shared Java state. Before raising concurrency, check for:

  • Mutable static fields, singleton page objects, or shared collections updated by several tests.
  • Tests that modify the same user account, database record, file, or other external resource.
  • Suite setup or teardown that assumes tests run one at a time.
  • Methods that depend on another test method having run first.

Give concurrent tests distinct data or explicit synchronization where sharing is intentional. If tests rely on order or shared class fixtures, use a grouping mode that respects those assumptions, or first refactor the tests so their state is isolated. Parallelizing an order-dependent suite can turn hidden dependencies into intermittent failures.

Scale beyond one local machine with Selenium Grid

Selenium Grid is designed to run suites in parallel across machines and browser types, versions, and operating systems. A local evaluation can use Grid in standalone mode and point a Java RemoteWebDriver at http://localhost:4444. Standalone runs Grid components on one machine; it is not a distributed, multi-machine deployment. Start from the Selenium project’s Grid getting-started guide, which covers setup and the endpoint.

A Java session can be created along these lines when the standalone server is available at that endpoint:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import java.net.URI;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.RemoteWebDriver;

WebDriver driver = new RemoteWebDriver(
    URI.create("http://localhost:4444").toURL(),
    new ChromeOptions()
);

Use the resulting driver in the same per-test lifecycle as a local driver and always call quit(). The requested browser must be available to Grid, and the client and server must be able to communicate. For a larger setup, choose standalone, Hub/Node, or distributed roles according to your machine count, desired browser matrix, session demand, and capacity. Selenium’s Grid guide notes that session creation depends on available processors, offers approximately 1 GB of RAM per browser as a planning reference, and cautions that actual requirements vary. Treat that figure as guidance, not a sizing guarantee; measure your own workload.

Grid also needs to be protected. Selenium warns that an exposed Grid can provide access to infrastructure and internal applications or let third parties run binaries. Restrict access with suitable firewall controls and do not expose a Grid endpoint publicly without appropriate security measures.

Set concurrency from observed capacity

More threads can reduce elapsed time only while the application, browser workers, and test infrastructure can keep up. Browser startup, CPU, memory, Grid slots, application response times, and shared test dependencies can become bottlenecks. A higher count can therefore slow the run or increase failures rather than improve throughput.

  1. Begin with a small thread-count and a suite whose tests have isolated drivers and data.
  2. Run the suite and inspect elapsed time, failure patterns, machine resource use, and available browser sessions.
  3. Increase the count in measured steps, comparing both runtime and stability rather than runtime alone.
  4. If the local machine becomes the bottleneck, move sessions to Grid workers or add suitable capacity before increasing the requested concurrency again.

Selenium’s documentation gives illustrative calculations, not guarantees: its example calculates 15 tests taking 45 seconds each as 11 minutes 15 seconds on one node, 2 minutes 15 seconds on five nodes, and 45 seconds on 15 nodes. Another example estimates 100 tests taking 120 seconds each at 13 minutes 20 seconds on 15 nodes. These simplified calculations do not account for setup, scheduling, dependencies, or resource contention, so real runs can differ.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The same Grid guide’s examples describe up to four concurrently created sessions at a four-CPU Distributor and up to eight sessions on an eight-CPU Node, except Safari is limited to one in that example. These are documented examples of defaults and capacity guidance, not universal limits or promises for every deployment.

Check TestNG pool settings against your version

Suite-level thread-count is not the only concurrency-related setting in TestNG. Data-provider execution has its own pool behavior and controls; the TestNG documentation reports a default of 10 threads for data-provider pools run from XML and says additional pool controls begin with TestNG 7.9.0. Check the documentation and configuration for the version actually used by your project rather than assuming a default from another version. The TestNG parameters documentation describes these controls.

Troubleshoot parallel runs

  • Tests pass alone but fail intermittently in parallel. Look for shared driver references, mutable static state, shared accounts or records, and order dependencies. Isolate data and resources, or choose a grouping mode that preserves the suite’s assumptions.
  • Browsers start slowly or sessions fail to start. The requested concurrency may exceed local CPU, RAM, or Grid availability. Reduce thread-count, inspect worker capacity, and increase resources or distribute sessions before trying a higher count.
  • Failures appear during teardown or later tests inherit stale state. Ensure teardown runs after failures, call quit(), and clean up any thread-local reference in a finally block.
  • RemoteWebDriver cannot reach Grid. Confirm the server is running, the client uses the correct reachable host and port, and Grid has the requested browser capability available. The documented local standalone endpoint is http://localhost:4444 when the client and server are on the same machine.
  • Changing suite threads does not change data-provider concurrency as expected. Check the project’s TestNG version and data-provider pool settings; those controls are distinct from simply choosing a suite parallel mode.
  • Grid works locally but should not be reachable by everyone. Limit network access with firewall rules and keep the Grid endpoint restricted to trusted clients.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Or skip the browser setup

If your task is to capture a page image or PDF rather than exercise it with Selenium assertions, ScreenshotNeo is a separate option: it is a website screenshot API and MCP server, not a replacement for a Selenium test suite. A single request can return an image or PDF:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation for request options. ScreenshotNeo accepts cookie/consent banners before capture and removes more than 60 known consent platforms, newsletter popups, and chat widgets; those steps can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, with response headers identifying the page verdict and billing status. Its MCP server offers take_screenshot, get_page_info, and capture_pdf for AI agents. The Free plan includes 1,000 screenshots per month without a card; paid plans start at $5 for 3,000 shots.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Sign up for ScreenshotNeo’s free plan to get 1,000 screenshots a month with no card.

For the core Selenium use case—interacting with a browser and verifying application behavior—TestNG and Selenium remain the relevant tools; a screenshot service is useful only when a capture itself is what you need.

Frequently Asked Questions

Can I use parallel=”methods” if my test methods share a class?

Only if the methods do not rely on mutable shared state or ordering. If they do, isolate that state or use a grouping mode that preserves the required execution context.

Does TestNG thread-count set the number of Grid machines?

No. It configures TestNG worker threads; Grid topology and available browser capacity are configured separately.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.