java中的静态Webdriver实例同步

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19067885/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 13:50:55  来源:igfitidea点击:

static Webdriver instance synchronization in java

javaseleniumselenium-webdrivertestngsynchronized

提问by Mrunal Gosar

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

GlobalVariables 类包含在我的框架中使用的不同变量,其中之一是 WebDriver 实例:

  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:

GlobalInitializer 包含初始化所有 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:

我有许多 GetElement 类,它们使用驱动程序实例来获取 UI 控制元素,例如:

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:

我有其他类在 UI 控件上执行一些操作(这些类也使用全局变量)例如:

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:

我在 testng 中的测试类如下所示:

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!

我有基于场景的类似的多个测试类。现在,如果我单独运行这些测试,则这些测试运行良好。但是当我尝试并行运行它们时,这个测试以某种奇怪的方式失败了。在分析时,我发现它的静态全局变量被每个测试初始化​​,从而使其他测试失败。现在我应该如何实现我的目标,在我的框架设计中以最小的变化并行运行多个测试?我曾尝试搜索选项,但我遇到了一些选项,即 1) 使用同步。2)创建 ThreadLocal 实例(注意:我已经尝试过这个解决方案,但仍然是同样的问题。测试相互混淆导致失败。我已将 WebDriver 实例标记为 ThreadLocal 并覆盖 ThreadLocal 的 initialValue 方法以初始化驱动程序实例。我仍然不确定我是否正确实施了它。)。现在我不确定在给定的场景中如何最好地实施任何一种解决方案。任何帮助表示赞赏。蒂亚!

采纳答案by Mrunal Gosar

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:

我找到了解决方案:使用 ThreadLocal 是在巨大的多线程环境中运行测试的最佳解决方案。在多线程环境中使用 WebDriver 的代码片段:

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.

现在,每次创建测试线程时都会打开一个新的浏览器。ThreadLocal 将确保每个线程只有一个静态 webdriver 实例的副本。[注意:确保您的其他全局变量也是 ThreadLocals。在我的情况下,它们不是我遇到测试错误问题的原因]。我想分享一些额外的知识,以便其他人可能会发现它很有用。在 ThreadLocal 中,无论何时调用 ThreadLocal.get() 方法,您都必须确保有一个条款来初始化本地线程,如上面的 initialValue() 方法所示,否则您可能会遇到空指针异常。谢谢大家。

回答by ddavison

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

您之所以会这样做,是因为 JVM 处理静态成员和方法的方式。

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

如果要并行运行,则不能拥有静态 webdriver 对象。

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

来源:我在我工作的地方实施的自动回归系统 - 我们遇到了这个问题。

回答by djangofan

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.

如果您要运行非并行,那么使用静态 webdriver 成员(或通过引用传递在测试类之间共享的实例)很好,因为这是不必在测试类之间关闭 webdriver 实例的好方法。但是,如果您想并行运行,则需要为每个线程创建一个 webdriver 实例,因此在这种情况下,使用静态成员是错误的方法。相反,您需要在调用测试用例类时创建或传递 webdriver 实例。

Also, you are breaking a test into separate tests for each step of the test. That is very unusualand 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.

此外,您将测试分解为每个测试步骤的单独测试。这是非常不寻常的,我不明白你这样做的原因。通过像人们通常做的那样将所有测试步骤保留在一个单一的测试用例中,您可以真正简化测试。

回答by ramkr

you can try something like this

你可以试试这样的

public class DriverManager {

公共类 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();
}

}

}