When you have decided to run your selenium’s tests in parallel, your Webdriver object should be thread-safe i.e. a single object can be used with multiple threads at the same time without causing problems. To achieve thread-safe have your choices are to pass that object around to every method that needs (or may need) it, or to associate the object with the thread.
You may not want to fill up your method signatures with an additional parameter. In a non-threaded world, you could solve the problem with the Java equivalent of a global variable. In a threaded word, the equivalent of a global variable is a thread-local variable.
In a single-threaded environment, Webdriver object will be a static field and return it as is. However, this will certainly not work in a multiple-threaded environment. Imagine if multiple threads used Webdriver object. Object used by each thread could overwrite each other since there is only one static instance of Webdriver.
In order to solve this problem, ThreadLocal provides a very good solution,
Now, you have your Thread local Webdriver object. Let's see how can you use it in your tests.
Just call getDriver() method from above class in the blocks or methods where ever you want. This will invoke your Webdriver and launches the browser. usage,
You have to initialize your Webdriver object local to the method or block only. Do not initialize it as a field or global object. If you want to use driver object in your test it should be,
After finishing your test you have to remove or quit the driver object and close the browser session. You need to be very careful about cleaning up any ThreadLocal's you
get()
by using the ThreadLocal's remove()
method. Like, you might want to remove or quit your ThreadLocal driver in teardown method like this,That's it. You are done. You can call getDriver() any number of times and any where, it will return you the same object all the time and the scope is limited to that thread only.
If I have three tests and run two in parallel this fails. The first two run fine but the third fails with a SessionNotFoundException. Any idea why I would be getting this error?
ReplyDeleteAh! Thank you for identifying. It's fixed now.
DeleteWhere is this fixed? Where can i find the "fixed" code?
DeleteHow can I add your solution to my code?Where can I add path to my IE Driver?
ReplyDeleteFile file = new File("C:/IEDriverServer_Win32_2.44.0/IEDriverServer.exe");
System.setProperty("webdriver.ie.driver", file.getAbsolutePath());
WebDriver driver = new InternetExplorerDriver();
This is incredibly clever. Thanks to you I understand the factory design pattern better.
ReplyDeletenot to mention, a good example of ThreadLocal
ReplyDeleteWhat was fixed for @conner t comments... Please let us know..
ReplyDeleteCould anyone kindly suggest what to do if I have to close the browser and relaunch it again
ReplyDeleteHi,
ReplyDeleteThanks for the article it seems like the solution I am looking for to implementing my driver. However, I do need to initialize my driver with desired capabilities that will change between methods/classes. Do you have any suggestions on how to do this?
Thanks
Jamie
This comment has been removed by the author.
ReplyDeleteHow to make cross browser executable?
ReplyDeletehow to make this work for setting up dynamically for any type of browser and passing this as parameter before running the tests ?
ReplyDeleteNormally the test class will have many test cases that share same instance of the driver: how to achieve this using ThreadLocal (@override ..?).
Thanks
This is what I am using for parallel execution but not sure if this is the correct way even though is working.
ReplyDelete// Usage
In the test do :
@BeforeTest
void setup(){
LocalDriverManager.createDriver(MyBrowserType.CHROME, 15);
}
@Test
test1(){
//get the driver
LocalDriverManager.getDriver().dosomething...
}
@Test
test2(){
//get the driver
LocalDriverManager.getDriver().dosomething...
}
/**
* if you need to execute many test cases in paraled in the same class
* change @BeforeTest to @BeforeMethod and use TestNG xml to run : [e.g thread-count="2" parallel="methods" ]
*
*/
public class LocalDriverManager {
private static final Logger logger = LoggerFactory.getLogger(LocalDriverManager.class);
private static final ThreadLocal threadLocalWebDriver = new ThreadLocal();
public static void createDriver(MyBrowserType browserType, int waitTimeSec){
logger.info("createDriver() :"+browserType.getBrowser());
WebDriver driver = LocalWebDriverFactory.getBrowser(browserType, waitTimeSec);
LocalDriverManager.setWebDriver(driver);
}
public static WebDriver getDriver() {
return threadLocalWebDriver.get();
}
private static void setWebDriver(WebDriver driver) {
threadLocalWebDriver.set(driver);
}
public static void unset() {
threadLocalWebDriver.remove();
}
public static void destroyLocalDriver(){
logger.info("destroyLocalDriver ...!");
if (getDriver() != null) {
getDriver().quit();
logger.info("Destroyed ...!");
}else {
logger.info("Not Destroyed ...is NULL ...!");
}
}
}
public class LocalWebDriverFactory extends RemoteWebDriver {
public static WebDriver getBrowser(MyBrowserType myBrowserType, int timeoutSeconds){
WebDriver driver = null;
try {
switch (myBrowserType) {
case FIREFOX:
driver = ThreadGuard.protect(new FirefoxDriver());
return driver;
case CHROME:
System.setProperty("webdriver.chrome.driver", CHROME_EXE_FILE);
driver = ThreadGuard.protect(new ChromeDriver());
return driver;
default:
logger.error("Cant find setup for browser : " + myBrowserType.getBrowser());
}
driver.manage().timeouts().implicitlyWait(timeoutSeconds, TimeUnit.SECONDS);
}catch (Exception e){
e.printStackTrace();
logger.error("Can't create browser ....! "+e.getMessage());
BaseCommunityPage.failTest(e, "Can not create browser :"+ myBrowserType.getBrowser());
}
return driver;
}
}
This works great for me with raw selenium in the test, but fails with cross-talk between concurrent tests when I pass the driver object to a page object to use methods from that object. Is there a way to make page objects thread safe too? Thanks for the great solution in any case!
ReplyDelete-Kent
This works great for me with raw selenium in the test, but fails with cross-talk between concurrent tests when I pass the driver object to a page object to use methods from that object. Is there a way to make page objects thread safe too? Thanks for the great solution in any case!
ReplyDelete-Kent
Thank you Krishna Kokkula, I dedicate the below lines for you:
ReplyDelete"Imparting knowledge is one of the greatest help to mankind"
Hi-
ReplyDeleteI have a cucumber framework in which I am trying to implement parallel execution. I have a SingletonDriver class which has a threadlocal variable as shown above. When I run 2 Test Runners parallely using testng.xml, two browsers open and navigate to the login page but after that point, the login process happens only in one browser and I get the message that 'The browser may have died.' Please help