使用非静态WebDriver进行并行执行 - Selenium - TestNG - Java

时间:2016-12-09 18:59:27

标签: java multithreading selenium selenium-webdriver testng

这是初始化ThreadLocal RemoteWebDriver的正确方法吗?

我见过帖子,人们说你不应该有静态WebDriver,但是,如果我删除静态修饰符,我最终会遇到NULL指针异常。

大多数情况下一切正常,但我遇到的问题是,一个线程偶尔会在不同的线程中输入数据。我试图解决导致我这个问题的问题。

TestSetup类:

public class TestSetup {

    private static ThreadLocal<RemoteWebDriver> threadDriver;// = new ThreadLocal<RemoteWebDriver>();

    @Parameters({"browserParam"})
    @BeforeClass(alwaysRun = true)
    public void beforeClass(@Optional("") final String browserParam) throws InterruptedException, MalformedURLException {

        // Set Driver
        threadDriver = new ThreadLocal<RemoteWebDriver>()
        {

            @Override
            protected RemoteWebDriver initialValue()
            {

                String browser = "Chrome";
                DesiredCapabilities dc = new DesiredCapabilities();

                if (browser.equals("Chrome"))
                {

                    String chromeDriver = "C:\\workspace\\drivers\\chromedriver.exe";
                    System.setProperty("webdriver.chrome.driver", chromeDriver);

                    // Access Grid Hub
                    dc.setBrowserName(DesiredCapabilities.chrome().getBrowserName());

                } // end Chrome

                // Set the driver
                try {
                    threadDriver.set(new RemoteWebDriver(new URL(hubURL), dc));
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                }

                return getDriver();

            } // end initialValue

        } // end threadDriver

    } // end beforeClass



    @AfterClass(alwaysRun = true)
    public void afterClass() {

        // Quit the Webdriver
        getDriver().quit();

    } // end afterClass



    public RemoteWebDriver getDriver() {

        return threadDriver.get();

    } // end getDriver

} // end TestSetup class

LoginTest类:

private Function perform = new Function();

@Test (retryAnalyzer = Retry.class, groups={"baseline", "negative"})
public synchronized void loginEmptyUsername() throws InterruptedException {

ExtentTest test = ExtentTestManager.getTest();

// Go to Secure
getDriver().get(StoredVariables.getsecureSite().get());

// Wait for password
perform.waitForElementToBeClickable(SLogin.password_txtbx(), "id");

// Clear email field
SLogin.email_txtbx(getDriver()).clear();

// enter password
SLogin.password_txtbx(getDriver()).clear();
SLogin.password_txtbx(getDriver()).sendKeys(StoredVariables.getpassword().get());

// click Sign In
SLogin.signIn_btn(getDriver()).click();

// Wait for error
perform.waitForElementToBeClickable(SLogin.loginError_txt(), "id");

// Verify error text
Assert.assertTrue(SLogin.loginError_txt(getDriver()).getText().contains("Oops! Your email or password (case sensitive) was incorrect. Please try again."));

// Log test
test.log(LogStatus.INFO, "login", "Tried logging in with an empty email");

} // end loginEmptyUsername

如果在TestSetup类中它不是静态的,我如何将WebDriver传递给测试类?

更新

似乎使用我的初始实现但限制Node只允许3个实例而不是使用最多5个实例已经解决了我的问题(至少目前)。

1 个答案:

答案 0 :(得分:0)

您不应该从方法中初始化ThreadLocal。您的实现取决于通过{"A":"`Welcome, ${user.name}`"}方法传入的浏览器风格,然后您的initialValue()实现将其用于实例化ThreadLocal并持久保存WebDriver实例。这个问题是下次当一些线程通过@BeforeClass查询你的线程本地时,如果有一个空值,那么调用将被路由到get(),但现在只记得最后一个浏览器参数。因此,您的总体实施需要折腾。

我写了一篇博文来解释这种行为。请看一下here

另外请记住,在保证执行相同的线程时,TestNG仅对initialValue()&gt;扩展此保证。 @BeforeMethod&gt; @Test组合。对于其他一切,没有这样的保证。

你也可以参考我的this博客,其中我谈到并行执行。

实现此目的的正确方法如下:

@AfterMethod