static Webdriver instance synchronization in java

2019-01-14 19:33发布

GlobalVariables class holds different variables which are used across my framework one of them is WebDriver instance:

  public class GlobalVariables
        {
        public static WebDriver driver;
    //Some other static global variables required across my framework
        public GlobalVariables(String propertiesFile)
        {
        initializeVariables(propertiesFile);
        }
        public void initializeVariables(String propertiesFile)
        {
        GlobalInitializer obj=new GlobalInitializer();
        obj.initialize(String propertiesFile);
        }
   }

GlobalInitializer contains methods to initialize all the GlobalVariables:

public class GlobalInitializer extends GlobalVariables
{
public void initialize(String propertiesFile)
{
  //Some logic to read properties file and based on the properties set in it, call other initialization methods to set the global variables.
}
public void initializeDriverInstance(String Browser)
{
driver=new FireFoxDriver();
}

//Some other methods to initialize other global variables. }

I have many GetElement classes which use the driver instance to get UI control elements E.g:

public class GetLabelElement extends GlobaleVariables
{
public static WebElement getLabel(String someID)
{
return driver.findElement(By.id(someId));
}
//Similar methods to get other types of label elements.
}

public class GetTextBoxElement extends GlobaleVariables
{
public static WebElement getTextBox(String someXpath)
{
return driver.findElement(By.xpath(someXpath));
}
//Similar methods to get other types of text box elements.
}

I have other classes which perform some actions on the UI Control(This classes too use the global variables) E.g:

public class GetLabelProperties extends GlobalVariables
{
public static String getLabelText(WebElement element)
{
return element.getText();
}
}

public class PerformAction extends GlobalVariables
{
public static void setText(String textBoxName,String someText)
{
driver.findElement(someLocator(textBoxName)).setText("someText");
}
    //Some other methods which may or may not use the global variables to perform some action
}

My test class in testng looks like this:

public class TestClass
{
GlobalVariables globalObj=new GlobalVariables(String propertiesFile);
@Test(priority=0)
{
GlobalVariables.driver.get(someURL);
//Some assertion.
}
@Test(priority=1)
{
WebElement element=GetLabelElement.getLabel(someID);
String labelName=GetLabelProperties.getLabelText(element);
//Some assertion.
}
@Test(priority=2)
{
WebElement element=GetTextBoxElement.getTextBox(someXpath);
PerformAction.setText(element.getText(),someText);
//Some assertion.
}
}

I have similar multiple test classes based on scenarios. Now this tests are running fine if i am running them individually. But when i try to run them in parallel, then this tests are failing in some weird fashion. On analyzing i found out that its the static global variables which are getting initialized by each tests thus leaving the other tests to fail. Now how should i go about achieving my objective to run multiple tests parallely with minimal changes in my framework design? i have tried searching for options, and i have come across some option i.e 1) use of synchronized. 2) Create ThreadLocal instance(Note : I have tried this solution but still same issue. tests are mixing up with each other resulting in failure. I had marked the WebDriver instance as ThreadLocal and overriden the initialValue method of ThreadLocal to initialize the driver instance. Still i am not sure whether i had implemented it correctly or not.). Now i am not sure how best to implement any one of this solution in the given scenario. Any help is appreciated. TIA!

4条回答
爱情/是我丢掉的垃圾
2楼-- · 2019-01-14 19:59

You are getting this because of how JVM handles static members and methods.

You can't have a static webdriver object if you are going to run in parallel.

Source: The automated regression system i implemented where I work - we had this issue.

查看更多
太酷不给撩
3楼-- · 2019-01-14 20:01

you can try something like this

public class DriverManager {

private static final ThreadLocal<WebDriver> threadLocal = new ThreadLocal<WebDriver>();

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

public static void setDriver(WebDriver driver) {
    threadLocal.set(driver);
}

public static void closeDriver() {
    if (getDriver() != null) {
        try {
            getDriver().close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            getDriver().quit();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    threadLocal.remove();
}

}

查看更多
神经病院院长
4楼-- · 2019-01-14 20:07

If you are going to run non-parallel, then using a static webdriver member (or a instance shared between test classes by passing by reference) is fine because it is a good way to not have to close the webdriver instance between test classes. If you want to run parallel though, you need to have one instance of webdriver for EACH thread and so in that case using a static member is the WRONG way to go. Instead you need to create or pass a webdriver instance when the test case class is invoked.

Also, you are breaking a test into separate tests for each step of the test. That is very unusual and I do not see the reason why you are doing that. You could really simplify your tests by keeping all the test steps within one singe test case like people usually do.

查看更多
5楼-- · 2019-01-14 20:09

I have found out the solution : Use of ThreadLocal is the best solution to run tests in a huge multithreaded environment. Code snippet to use WebDriver in multithreaded environment:

public static ThreadLocal<WebDriver> driver;
driver=new ThreadLocal<WebDriver>()
                {
                    @Override
                    protected WebDriver initialValue()
                    {
                        return new FirefoxDriver(); //You can use other driver based on your requirement.
                    }
                };

Now every time a test thread is created a new browser will open. ThreadLocal will make sure that there's only one copy of static webdriver instance per thread. [NOTE: Make sure your other global variables are too ThreadLocals. In my case they were not thats why i was running into test goof up issue]. Some extra knowledge which i would like to share so that others may find it informative. In ThreadLocal whenever the ThreadLocal.get() method is called you have to make sure that there is a provision to initialize the thread local as shown above in initialValue() method or you may run into null pointer exception. Thanks everyone.

查看更多
登录 后发表回答