Mastering Parallel Test Execution Using Selenium

Parallel Test Execution Using Selenium

As Selenium test suites grow in size and complexity, running tests sequentially becomes a major bottleneck. That’s where parallel test execution in Selenium comes in allowing you to execute multiple tests simultaneously using tools like TestNG and Selenium Grid.

In this guide, you’ll explore how to run test cases in parallel using TestNG, with hands-on examples and configurations. We’ll also look at how to set up parallel execution in Selenium with tools like Selenium Grid for large-scale scalability

What is Parallel Test Execution?

Parallel execution is a technique to run tests simultaneously rather than sequentially. Instead of running one test after another, tests are split and executed across different threads or environments, drastically reducing execution time.

Imagine having 100 test cases, which take one minute each to execute. If executed one after the other(sequentially), the suite takes 100 minutes to run. But if we run 10 tests at a time in parallel(with 10 threads), the suite can finish in approximately 10 minutes. This can make a huge difference, especially when tests are triggered frequently in CI/CD pipelines.

Why is Parallel Testing Important?

  • Faster execution: Running Selenium tests in parallel significantly reduces the execution time.
  • Improved coverage: More scenarios can be covered in the same time frame by executing tests simultaneously across different browsers, operating systems, and device types.
  • Cost efficiency: Reduces infrastructure load and resource costs by leveraging parallel execution.
  • Scalability: As the project grows, so does the number of test cases. Parallel tests can easily adapt to large-scale automation frameworks in CI/CD pipelines by increasing the test coverage without a proportional increase in test duration.

Principles of Building Parallel Ready Tests

To build parallel tests, it is important that the test cases be:

  • Atomic: The tests should not be dependent on the results of other tests. One test = one functionality.
  • Independent: Each test should maintain its own setup and tear down.
  • Stateless: Tests should not rely on shared memory or data.
  • Isolated Environments: Each test should use a separate browser session or mock data.

These principles are especially crucial when scaling tests through Selenium parallel execution environments like TestNG or Grid.

How to Run Selenium Tests in Parallel Using TestNG

Parallel test execution in Selenium can be achieved by using the TestNG framework. Let us discuss some approaches to running tests in parallel using Selenium.

Using TestNG’s parallel Attribute

TestNG is one of the most widely used testing frameworks with Selenium. By configuring its XML file, you can run tests in parallel.

Parallel Methods Example

In our example, we will write two test methods-

  1. One that would open google.com
  2. Another that would open bing.com

We will run these methods in parallel using the parallel attribute at the method level.

Below is the Java code to open the Google browser and navigate to different URLs through different test methods.

package parallelExecution;
import org.testng.annotations.Test;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class ParallelTestExecution {
	 	@Test
	    public void testGoogle() {
	        WebDriver driver = new ChromeDriver();
	        driver.get("https://www.google.com");
	        System.out.println("Title: " + driver.getTitle());
	        driver.quit();
	    }
	    @Test
	    public void testBing() {
	        WebDriver driver = new ChromeDriver();
	        driver.get("https://www.bing.com");
	        System.out.println("Title: " + driver.getTitle());
	        driver.quit();
	    }
}

Below is the testng.xml file with the parallel attribute to run the test methods in the Java code in parallel.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite thread-count="2" parallel="methods" name="Suite">
 <test name="Test">
   <classes>
     <class name="parallelExecution.ParallelTestExecution"/>
   </classes>
 </test> <!-- Test -->
</suite> <!-- Suite -->

When you run the testng.xml file, you will notice that two browsers are invoked and the tests run in parallel, reducing your execution time.

Below are the console logs of execution.

Parallel Test  console logs of execution.

Parallel Execution by Classes or Tests

Another way to achieve parallel test execution is by parallelizing at the class or test level.

Let us look at the example below, where we have written the same test that we used above in two different classes.

Class One:

package parallelExecution;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.Test;
public class ParallelTestA {
	@Test
   public void testGoogle() {
       WebDriver driver = new ChromeDriver();
       driver.get("https://www.google.com");
       System.out.println("Title: " + driver.getTitle());
       driver.quit();
   }
}

Class two:

package parallelExecution;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.Test;
public class ParallelTestB {
   @Test
   public void testBing() {
       WebDriver driver = new ChromeDriver();
       driver.get("https://www.bing.com");
       System.out.println("Title: " + driver.getTitle());
       driver.quit();
   }
}

Testng.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite thread-count="2" parallel="classes" name="Suite">
 <test name="Test">
   <classes>
     <class name="parallelExecution.ParallelTestA"/>
     <class name="parallelExecution.ParallelTestB"/>
   </classes>
 </test> <!-- Test -->
</suite> <!-- Suite -->

On running the testng.xml, you will notice that the test classes execute in parallel.

Parallel Execution by Classes or Tests

Thread Safety in Parallel Execution

When you run Selenium tests in parallel, multiple test cases are running at the same time, on different threads. This reduces the overall execution time but also introduces a challenge- the race condition. If multiple threads try to use the same WebDriver instance, they can interfere with each other and cause test failures. The WebDriver instances need to be isolated between the tests to avoid this issue. This can be done using the Thread Local class provided by Java, which lets each thread have its own copy of the variable.

Let us see how the same can be implemented in Selenium. We will create a WebDriver factory class that will create a separate WebDriver object for each thread.

package parallelExecution;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
public class DriverFactory {
   // This creates a separate WebDriver object for each thread
   private static ThreadLocal<WebDriver> driver = new ThreadLocal<>();
   // This method gives you the WebDriver for the current thread
   public static WebDriver getDriver() {
       if (driver.get() == null) {
           // If no driver exists for this thread, create a new one
           driver.set(new ChromeDriver()); // You can change to FirefoxDriver or use parameters
       }
       return driver.get(); // Return the WebDriver for the current thread
   }
   // This method closes and removes the driver from the current thread
   public static void quitDriver() {
       if (driver.get() != null) {
           driver.get().quit();   // Close the browser
           driver.remove();       // Remove the driver from memory
       }
   }

Your test class will look like this

package parallelExecution;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class ParallelTestThreadSafe {
	    @BeforeMethod
	    public void setup() {
	        DriverFactory.getDriver().manage().window().maximize();
	    }
	    @Test
	    public void openGoogle() {
	        DriverFactory.getDriver().get("https://google.com");
	    }
	    @Test
	    public void openBing() {
	        DriverFactory.getDriver().get("https://bing.com");
	    }
	    @AfterMethod
	    public void tearDown() {
	        DriverFactory.quitDriver();
	    }
	
}

You can now execute your testng.xml, and each of the tests will get its own browser, which runs independently of others.

While TestNG enables parallel threads, you will hit limits on a local machine. This is where you can scale your frameworks by using Selenium Grid, which will allow you to run your tests across multiple machines and browsers in parallel.

Infrastructure Strategies for Parallel Testing

To run tests in parallel, a test infrastructure that allows concurrent execution is required.

Local Execution

Local execution in parallel is best suited for small test suites or during development. You can execute parallel tests using multiple threads on your local machine.

Selenium Grid

Selenium Grid allows you to distribute tests across multiple machines. It uses Hub and Nodes to run tests across multiple browsers in parallel.

If you’re unfamiliar with Selenium Grid, you can learn more in our detailed Selenium Grid tutorial to get started with hub-node configurations.

Cloud-Based Platforms like TestGrid

Cloud platforms like TestGrid provide scalability beyond local hardware. They provide access to a wide range of real devices and browsers along with easy to use dashboards and logs. The hassle of infrastructure management is reduced and you can scale your automation test suites for enterprise-grade testing.

Challenges of Parallel Testing

Parallel test execution has many advantages, but it comes with its own set of challenges.

  • Race Conditions: If two resources access shared resources simultaneously, one might overwrite or corrupt the other’s data.
  • Flaky Tests: Due to poor isolation or timing issues, tests may sometimes pass or sometimes fail.
  • Complex Debugging: Debugging parallel tests can be complex because logs may be intertwined.
  • Infrastructure Bottlenecks: On local machines, running tests in parallel can overwhelm CPU, memory or network resources.
  • Longer Setup Time: Creating independent and thread-safe tests is time taking. It is a trade-off between upfront design effort and long-term execution speed.

Best Practices for Selenium Parallel Execution

  • Use ThreadLocal to manage WebDriver instances safely in Selenium parallel execution contexts.
  • To escape flaky tests, avoid using shared variables or static WebDriver across tests.
  • Use the @AfterMethod annotation to clean up resources after each test method.
  • Use cloud-based infrastructure like TestGrid to scale horizontally.

Final Thoughts

Modern automation pipelines need parallel execution as a necessity. Whether you are a small QA team optimizing test cycles or an enterprise running thousands of regression tests daily, adopting parallel execution with Selenium, TestNG, and platforms like TestGrid ensures faster feedback, improved ROI, and agile QA. By deploying the right execution approach with the desirable infrastructure strategy, your team can not just scale the test automation frameworks but marginally reduce the time it takes to execute them.

Whether you’re working with small suites or enterprise frameworks, parallel execution in TestNG and Selenium Grid parallel execution can drastically improve automation efficiency when implemented correctly.