ThreadLocal Static WebDriver For Parallel Execution

In previous post, we learnt How a static WebDriver reference created problems in parallel execution. We will see solution of those problems in this post.

Please note I am exclusively using a static WebDriver reference but similar solution will be applicable for any static reference.

Solution I have already discussed in my previous post. We need to use ThreadLocal so that each thread will have their own reference to class variables including static class variables. Read more about ThreadLocal at my blog here.

Let’s declare a static WebDriver as ThreadLocal. I have created simple methods to set, get and remove driver.

Class WebDriverFactoryStaticThreadLocal :-

package SolvingParallelRunProblemWithStaticWebDriverUsingThreadLocal;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;

import io.github.bonigarcia.wdm.WebDriverManager;

public class WebDriverFactoryStaticThreadLocal {
	
	private static ThreadLocal driver = new ThreadLocal();
	
	public static  void setDriver() {
		WebDriverManager.chromedriver().setup();
		driver.set(new ChromeDriver());
	}
	
	public static WebDriver getDriver()
	{
		return driver.get();
	}
	
	public static void closeBrowser()
	{
		driver.get().close();
		driver.remove();
	}
	

}

Little changes to TestNG test classes to use driver instance using getter method and calling close method from WebDriverFactoryStaticThreadLocal class.

Class TestOneWithStaticWebDriver

package SolvingParallelRunProblemWithStaticWebDriverUsingThreadLocal;

import java.lang.reflect.Method;

import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;


public class TestOneWithStaticWebDriver {
	
	@BeforeClass
	public void setUp()
	{
		WebDriverFactoryStaticThreadLocal.setDriver();
		System.out.println("Browser setup by Thread "+Thread.currentThread().getId()+" and Driver reference is : "+WebDriverFactoryStaticThreadLocal.getDriver());
	}

	@Test
	public void GoogleTest(Method m) throws InterruptedException
	{
		System.out.println(m.getName()+" of class TestOneWithStaticWebDriver Executed by Thread "+Thread.currentThread().getId()+" on driver reference "+WebDriverFactoryStaticThreadLocal.getDriver());
		WebDriverFactoryStaticThreadLocal.getDriver().get("https://www.google.com/");
		Thread.sleep(15000);
		System.out.println("Title printed by Thread "+Thread.currentThread().getId()+" - "+WebDriverFactoryStaticThreadLocal.getDriver().getTitle()+" on driver reference "+WebDriverFactoryStaticThreadLocal.getDriver());
		WebDriverFactoryStaticThreadLocal.getDriver().manage().deleteAllCookies();
	}
	
	@Test
	public void FacebookTest(Method m) throws InterruptedException
	{
		System.out.println(m.getName()+" of class TestOneWithStaticWebDriver Executed by Thread "+Thread.currentThread().getId()+" on driver reference "+WebDriverFactoryStaticThreadLocal.getDriver());
		WebDriverFactoryStaticThreadLocal.getDriver().get("https://www.facebook.com/");
		Thread.sleep(15000);
		System.out.println("Title printed by Thread "+Thread.currentThread().getId()+" - "+WebDriverFactoryStaticThreadLocal.getDriver().getTitle()+" on driver reference "+WebDriverFactoryStaticThreadLocal.getDriver());
		WebDriverFactoryStaticThreadLocal.getDriver().manage().deleteAllCookies();
		
	}
	
	@AfterClass
	public void tearDown()
	{
		System.out.println("Browser closed by Thread "+Thread.currentThread().getId() + " and Closing driver reference is :"+WebDriverFactoryStaticThreadLocal.getDriver());
		WebDriverFactoryStaticThreadLocal.closeBrowser();
	}
}

Class TestTwoWithStaticWebDriver :-

package SolvingParallelRunProblemWithStaticWebDriverUsingThreadLocal;

import java.lang.reflect.Method;

import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;


public class TestTwoWithStaticWebDriver {
	
	@BeforeClass
	public void setUp() throws InterruptedException
	{
		WebDriverFactoryStaticThreadLocal.setDriver();
		System.out.println("Browser setup by Thread "+Thread.currentThread().getId()+" and Driver reference is : "+WebDriverFactoryStaticThreadLocal.getDriver());
	}
	

	@Test
	public void FlipkartTest(Method m) throws InterruptedException
	{
		System.out.println(m.getName()+" of class TestOneWithStaticWebDriver Executed by Thread "+Thread.currentThread().getId()+" on driver reference "+WebDriverFactoryStaticThreadLocal.getDriver());
		WebDriverFactoryStaticThreadLocal.getDriver().get("https://www.flipkart.com/");
		Thread.sleep(15000);
		System.out.println("Title printed by Thread "+Thread.currentThread().getId()+" - "+WebDriverFactoryStaticThreadLocal.getDriver().getTitle()+" on driver reference "+WebDriverFactoryStaticThreadLocal.getDriver());
		WebDriverFactoryStaticThreadLocal.getDriver().manage().deleteAllCookies();
		
	}
	
	@Test
	public void MyntraTest(Method m) throws InterruptedException
	{
		System.out.println(m.getName()+" of class TestOneWithStaticWebDriver Executed by Thread "+Thread.currentThread().getId()+" on driver reference "+WebDriverFactoryStaticThreadLocal.getDriver());
		WebDriverFactoryStaticThreadLocal.getDriver().get("https://www.myntra.com/");
		Thread.sleep(15000);
		System.out.println("Title printed by Thread "+Thread.currentThread().getId()+" - "+WebDriverFactoryStaticThreadLocal.getDriver().getTitle()+" on driver reference "+WebDriverFactoryStaticThreadLocal.getDriver());
		WebDriverFactoryStaticThreadLocal.getDriver().manage().deleteAllCookies();
		
	}
	
	@AfterClass
	public void tearDown()
	{
		System.out.println("Browser closed by Thread "+Thread.currentThread().getId() + " and Closing driver reference is :"+WebDriverFactoryStaticThreadLocal.getDriver());
		WebDriverFactoryStaticThreadLocal.closeBrowser();
	}
}

Let’s execute TestNG classes in parallel using TestNG xml as below:-




  
    
      
      
    
   
 

Output:-

Starting ChromeDriver 80.0.3987.106 (f68069574609230cf9b635cd784cfb1bf81bb53a-refs/branch-heads/3987@{#882}) on port 10510
Only local connections are allowed.
Please protect ports used by ChromeDriver and related test frameworks to prevent access by malicious code.

Starting ChromeDriver 80.0.3987.106 (f68069574609230cf9b635cd784cfb1bf81bb53a-refs/branch-heads/3987@{#882}) on port 22228
Only local connections are allowed.
Please protect ports used by ChromeDriver and related test frameworks to prevent access by malicious code.

Browser setup by Thread 12 and Driver reference is : ChromeDriver: chrome on WINDOWS (cb5584647d45d743f09ac3d56cc7d5eb)
FlipkartTest of class TestOneWithStaticWebDriver Executed by Thread 12 on driver reference ChromeDriver: chrome on WINDOWS (cb5584647d45d743f09ac3d56cc7d5eb)

Browser setup by Thread 11 and Driver reference is : ChromeDriver: chrome on WINDOWS (688aef6ce3b1d097ccb472605a11cda1)
FacebookTest of class TestOneWithStaticWebDriver Executed by Thread 11 on driver reference ChromeDriver: chrome on WINDOWS (688aef6ce3b1d097ccb472605a11cda1)

Title printed by Thread 12 - Online Shopping Site for Mobiles, Electronics, Furniture, Grocery, Lifestyle, Books & More. Best Offers! on driver reference ChromeDriver: chrome on WINDOWS (cb5584647d45d743f09ac3d56cc7d5eb)
MyntraTest of class TestOneWithStaticWebDriver Executed by Thread 12 on driver reference ChromeDriver: chrome on WINDOWS (cb5584647d45d743f09ac3d56cc7d5eb)

Title printed by Thread 11 - Facebook – log in or sign up on driver reference ChromeDriver: chrome on WINDOWS (688aef6ce3b1d097ccb472605a11cda1)
GoogleTest of class TestOneWithStaticWebDriver Executed by Thread 11 on driver reference ChromeDriver: chrome on WINDOWS (688aef6ce3b1d097ccb472605a11cda1)

Title printed by Thread 12 - Online Shopping for Women, Men, Kids Fashion & Lifestyle - Myntra on driver reference ChromeDriver: chrome on WINDOWS (cb5584647d45d743f09ac3d56cc7d5eb)
Title printed by Thread 11 - Google on driver reference ChromeDriver: chrome on WINDOWS (688aef6ce3b1d097ccb472605a11cda1)

Browser closed by Thread 12 and Closing driver reference is :ChromeDriver: chrome on WINDOWS (cb5584647d45d743f09ac3d56cc7d5eb)
Browser closed by Thread 11 and Closing driver reference is :ChromeDriver: chrome on WINDOWS (688aef6ce3b1d097ccb472605a11cda1)

===============================================
Suite
Total tests run: 4, Passes: 4, Failures: 0, Skips: 0
===============================================

Observe output and find how driver reference were kept separately for both threads and how ThreadLocal helped in that.

Let’s dig further little more.

Above we ran TestNG class in parallel. What will happen if we run @Test methods in parallel.

Let’s run by changing parallel attribute as below:-




  
    
      
      
    
   
 

Output:-

Starting ChromeDriver 80.0.3987.106 (f68069574609230cf9b635cd784cfb1bf81bb53a-refs/branch-heads/3987@{#882}) on port 8922
Only local connections are allowed.
Please protect ports used by ChromeDriver and related test frameworks to prevent access by malicious code.

Browser setup by Thread 11 and Driver reference is : ChromeDriver: chrome on WINDOWS (09b76840ac98cadec934d88834e1d10f)

FacebookTest of class TestOneWithStaticWebDriver Executed by Thread 11 on driver reference ChromeDriver: chrome on WINDOWS (09b76840ac98cadec934d88834e1d10f)

GoogleTest of class TestOneWithStaticWebDriver Executed by Thread 12 on driver reference null

Starting ChromeDriver 80.0.3987.106 (f68069574609230cf9b635cd784cfb1bf81bb53a-refs/branch-heads/3987@{#882}) on port 21202
Only local connections are allowed.
Please protect ports used by ChromeDriver and related test frameworks to prevent access by malicious code.

Browser setup by Thread 12 and Driver reference is : ChromeDriver: chrome on WINDOWS (d2c3ccddb813d65c161e7ddef78c69e1)

FlipkartTest of class TestOneWithStaticWebDriver Executed by Thread 12 on driver reference ChromeDriver: chrome on WINDOWS (d2c3ccddb813d65c161e7ddef78c69e1)

Title printed by Thread 11 - Facebook – log in or sign up on driver reference ChromeDriver: chrome on WINDOWS (09b76840ac98cadec934d88834e1d10f)

Browser closed by Thread 11 and Closing driver reference is :ChromeDriver: chrome on WINDOWS (09b76840ac98cadec934d88834e1d10f)

Title printed by Thread 12 - Online Shopping Site for Mobiles, Electronics, Furniture, Grocery, Lifestyle, Books & More. Best Offers! on driver reference ChromeDriver: chrome on WINDOWS (d2c3ccddb813d65c161e7ddef78c69e1)

MyntraTest of class TestOneWithStaticWebDriver Executed by Thread 12 on driver reference ChromeDriver: chrome on WINDOWS (d2c3ccddb813d65c161e7ddef78c69e1)

Title printed by Thread 12 - Online Shopping for Women, Men, Kids Fashion & Lifestyle - Myntra on driver reference ChromeDriver: chrome on WINDOWS (d2c3ccddb813d65c161e7ddef78c69e1)
Browser closed by Thread 12 and Closing driver reference is :ChromeDriver: chrome on WINDOWS (d2c3ccddb813d65c161e7ddef78c69e1)

===============================================
Suite
Total tests run: 4, Passes: 3, Failures: 1, Skips: 0
===============================================

Again something unexpected happen and one test could not find a browser to execute on. Reason behind this is that @BeforeClass and @AfterClass will not be executed for each @Test annotated methods if we run them in parallel. We were expecting that since we are running @Test methods in parallel, @BeforeClass and @AfterClass for each test methods will be called but it does not work in that way. You may ask what will happen if we set thread count as 4 which is equal to test method. Try that as well. You will see two threads will have browser to execute test but another two threads will have null driver reference.

Output:-

Starting ChromeDriver 80.0.3987.106 (f68069574609230cf9b635cd784cfb1bf81bb53a-refs/branch-heads/3987@{#882}) on port 23221
Only local connections are allowed.
Please protect ports used by ChromeDriver and related test frameworks to prevent access by malicious code.

Starting ChromeDriver 80.0.3987.106 (f68069574609230cf9b635cd784cfb1bf81bb53a-refs/branch-heads/3987@{#882}) on port 32111
Only local connections are allowed.
Please protect ports used by ChromeDriver and related test frameworks to prevent access by malicious code.

Browser setup by Thread 11 and Driver reference is : ChromeDriver: chrome on WINDOWS (583d8dfe75d4a363ad23ab034070667e)

FacebookTest of class TestOneWithStaticWebDriver Executed by Thread 11 on driver reference ChromeDriver: chrome on WINDOWS (583d8dfe75d4a363ad23ab034070667e)

GoogleTest of class TestOneWithStaticWebDriver Executed by Thread 12 on driver reference null

Browser setup by Thread 13 and Driver reference is : ChromeDriver: chrome on WINDOWS (043c2560edb033c8206eb14691ed64d4)

FlipkartTest of class TestOneWithStaticWebDriver Executed by Thread 13 on driver reference ChromeDriver: chrome on WINDOWS (043c2560edb033c8206eb14691ed64d4)

MyntraTest of class TestOneWithStaticWebDriver Executed by Thread 14 on driver reference null

Title printed by Thread 13 - Online Shopping Site for Mobiles, Electronics, Furniture, Grocery, Lifestyle, Books & More. Best Offers! on driver reference ChromeDriver: chrome on WINDOWS (043c2560edb033c8206eb14691ed64d4)

Browser closed by Thread 13 and Closing driver reference is :ChromeDriver: chrome on WINDOWS (043c2560edb033c8206eb14691ed64d4)

Title printed by Thread 11 - Facebook – log in or sign up on driver reference ChromeDriver: chrome on WINDOWS (583d8dfe75d4a363ad23ab034070667e)

Browser closed by Thread 11 and Closing driver reference is :ChromeDriver: chrome on WINDOWS (583d8dfe75d4a363ad23ab034070667e)

===============================================
Suite
Total tests run: 4, Passes: 2, Failures: 2, Skips: 0
===============================================

Since tests execution requires browsers, so we need to change BeforeClass and AfterClass to BeforeMethod and AfterMethod. Change it and run.

Output:-

Starting ChromeDriver 80.0.3987.106 (f68069574609230cf9b635cd784cfb1bf81bb53a-refs/branch-heads/3987@{#882}) on port 8979
Only local connections are allowed.
Please protect ports used by ChromeDriver and related test frameworks to prevent access by malicious code.

Starting ChromeDriver 80.0.3987.106 (f68069574609230cf9b635cd784cfb1bf81bb53a-refs/branch-heads/3987@{#882}) on port 40461
Only local connections are allowed.
Please protect ports used by ChromeDriver and related test frameworks to prevent access by malicious code.

Browser setup by Thread 12 and Driver reference is : ChromeDriver: chrome on WINDOWS (973c57935ea39165f83a18ae70792aef)

GoogleTest of class TestOneWithStaticWebDriver Executed by Thread 12 on driver reference ChromeDriver: chrome on WINDOWS (973c57935ea39165f83a18ae70792aef)

Browser setup by Thread 11 and Driver reference is : ChromeDriver: chrome on WINDOWS (fb9c461922b6272fcf813d43fd66edd0)

FacebookTest of class TestOneWithStaticWebDriver Executed by Thread 11 on driver reference ChromeDriver: chrome on WINDOWS (fb9c461922b6272fcf813d43fd66edd0)

Title printed by Thread 12 - Google on driver reference ChromeDriver: chrome on WINDOWS (973c57935ea39165f83a18ae70792aef)

Browser closed by Thread 12 and Closing driver reference is :ChromeDriver: chrome on WINDOWS (973c57935ea39165f83a18ae70792aef)

Title printed by Thread 11 - Facebook – log in or sign up on driver reference ChromeDriver: chrome on WINDOWS (fb9c461922b6272fcf813d43fd66edd0)

Starting ChromeDriver 80.0.3987.106 (f68069574609230cf9b635cd784cfb1bf81bb53a-refs/branch-heads/3987@{#882}) on port 31716
Only local connections are allowed.
Please protect ports used by ChromeDriver and related test frameworks to prevent access by malicious code.

Browser closed by Thread 11 and Closing driver reference is :ChromeDriver: chrome on WINDOWS (fb9c461922b6272fcf813d43fd66edd0)

Starting ChromeDriver 80.0.3987.106 (f68069574609230cf9b635cd784cfb1bf81bb53a-refs/branch-heads/3987@{#882}) on port 20172
Only local connections are allowed.
Please protect ports used by ChromeDriver and related test frameworks to prevent access by malicious code.

Browser setup by Thread 12 and Driver reference is : ChromeDriver: chrome on WINDOWS (c4e227a725fa2209611bf4fb12eb1dfa)

FlipkartTest of class TestOneWithStaticWebDriver Executed by Thread 12 on driver reference ChromeDriver: chrome on WINDOWS (c4e227a725fa2209611bf4fb12eb1dfa)

Browser setup by Thread 11 and Driver reference is : ChromeDriver: chrome on WINDOWS (d67145a966ee60d0fae790b60efb60a4)

MyntraTest of class TestOneWithStaticWebDriver Executed by Thread 11 on driver reference ChromeDriver: chrome on WINDOWS (d67145a966ee60d0fae790b60efb60a4)

Title printed by Thread 12 - Online Shopping Site for Mobiles, Electronics, Furniture, Grocery, Lifestyle, Books & More. Best Offers! on driver reference ChromeDriver: chrome on WINDOWS (c4e227a725fa2209611bf4fb12eb1dfa)

Browser closed by Thread 12 and Closing driver reference is :ChromeDriver: chrome on WINDOWS (c4e227a725fa2209611bf4fb12eb1dfa)

Title printed by Thread 11 - Online Shopping for Women, Men, Kids Fashion & Lifestyle - Myntra on driver reference ChromeDriver: chrome on WINDOWS (d67145a966ee60d0fae790b60efb60a4)

Browser closed by Thread 11 and Closing driver reference is :ChromeDriver: chrome on WINDOWS (d67145a966ee60d0fae790b60efb60a4)

===============================================
Suite
Total tests run: 4, Passes: 4, Failures: 0, Skips: 0
===============================================

You can download code form this repo.

If you have any doubt, feel free to comment below.
If you like my posts, please like, comment, share and subscribe.
#ThanksForReading
#HappyLearning

You can find all Selenium related post here.
You can find all API manual and automation related posts here.
You can find frequently asked Java Programs here.

5 thoughts on “ThreadLocal Static WebDriver For Parallel Execution

  1. Hi Amod,

    I am using docker selenium grid and running our script parallelly by test tag but 1 test case is getting failed. Can you please help me?
    Here is the testng file-

    Here is the driver launch code-

    protected static ThreadLocal driver = new ThreadLocal();

    public static void intializeRemoteBrowser(String browserType) throws MalformedURLException {
    DesiredCapabilities cap = new DesiredCapabilities();
    if (browserType.equalsIgnoreCase(“chrome”)) {
    cap.setBrowserName(BrowserType.CHROME);
    WebDriverManager.chromedriver().setup();
    System.out.println(“########### TEST CASE EXECUTION STARTED ON ==>” + browserType+” : “+ Thread.currentThread().getId());
    }

    else if (browserType.equalsIgnoreCase(“firefox”)) {
    cap.setBrowserName(BrowserType.FIREFOX);
    WebDriverManager.firefoxdriver().setup();
    System.out.println(“########### TEST CASE EXECUTION STARTED ON ==>” + browserType+” : “+ Thread.currentThread().getId());
    }

    public static WebDriver getDriver() {
    return driver.get();
    }

    public static void closeBrowser() {
    driver.get().close();
    driver.remove();
    System.out.println(“###############TEST CASES EXECUTION ENDED###############”+” : “+ Thread.currentThread().getId());
    }

  2. Hi Amod, can I use the same code in case of multiple browsers as well? My existing code has else if statements for different browsers.

  3. Hi Amod can you explain regarding failure when it’s @BeforeClass @AfterClass Scenario with parallel = methods. Step by Step .

Leave a Reply

Your email address will not be published. Required fields are marked *