【问题标题】:TestNG Selenium with parallel threads具有并行线程的 TestNG Selenium
【发布时间】:2017-08-10 20:13:43
【问题描述】:

我已经看到了很多关于这个主题的问题,但似乎没有一个与我正在寻找的内容有关。我试图在单个类下运行并行方法,使用@BeforeMethod 启动浏览器,@AfterMethod 拆除浏览器。对于这个例子,假设它是一个单一的类文件,里面有几个测试方法。我希望在不同的浏览器中同时运行其中的 4 个。我们正在使用 Groovy,但一个 Java 答案就足够了。

XML:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >

<suite name="sampleSuite" thread-count="4" preserve-order="true" parallel="methods">
    <test name="sample">
        <classes>
            <class name="tests.some.class.MyClassFile"/>
        </classes>
    </test>
</suite>

DriverFactory 类,负责简单地创建和返回浏览器:

private static WebDriver createWebDriver() {
    String property = System.getProperty("driver", "chrome")
    def capabilities

    if (property == "chrome") {
        capabilities = DesiredCapabilities.chrome()


    } else if (property == "firefox") {
        System.setProperty("webdriver.gecko.driver", "/usr/local/Cellar/geckodriver/0.16.1/bin/geckodriver")
        capabilities = DesiredCapabilities.firefox()
    }

    def url = System.getProperty("seleniumServerUrl", "http://localhost:4444/wd/hub")

    if (!url) {
        throw new IllegalStateException("No 'seleniumServerUrl' system property set")
    }

    def webDriver = new RemoteWebDriver(new URL(url), capabilities)
    webDriver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS)
    webDriver.manage().window().setSize(new Dimension(1920,1080))

    Runtime.addShutdownHook {
        try {
            webDriver.quit()
        } catch (ignore) {}
    }
    webDriver
}

对于线程,也在 DriverFactory 类中:

static final WebDriver createStackWebDriver(){
    ThreadLocal<WebDriver> webDriver = new ThreadLocal<WebDriver>(){
        protected WebDriver initialValue(){
            createWebDriver()
        }
    }
    webDriver.get()
}

现在我有一个 TestPlatform 类,它是架构的核心“设置和拆除”部分。我所有包含 @Test 方法的类文件都扩展了这个 TestPlatform 类:

class TestPlatform {

    WebDriver webDriver

    @BeforeMethod
    void startUpWebBrowser(){
        webDriver = DriverFactory.createStackWebDriver()
    }

    @AfterMethod
    void quitWebDriver(){
        webDriver.quit()
    }
}

当我们运行 XML 文件时,我们看到的是 4 个 startUpWebBrowser() 实例,4 个中的一个会“通过”并继续测试,它会立即打开一个 @987654329 实例中的 4 个方法@,而其他 3 只保持“挂起”。我们需要它在每个 startUpWebBrowser() 实例中打开一个浏览器,而不是在一个实例中打开 4 个浏览器。

我们当前的解决方法是将每个@Test 方法包装在其自己的类中,并将@BeforeMethod 更改为@BeforeClass 以及后面的内容。这在某种程度上可行,但在报告方面非常难看,而且这种方式还有其他一些缺点。

在不对当前架构进行大修的情况下,是否有解决此问题的方法?我只是错过了一些非常简单的东西吗?

【问题讨论】:

  • TestPlatform 中的 webdriver 变量不是线程安全的。将 ThreadLocal 变量作为 static final 移动到 TestPlatform 类中并在 initialValue 方法中调用 DriverFactory.createWebDriver() 会不会更简单。不需要 before 方法,因为您可以在测试方法中的 threadlocal 变量上使用 get() 来获取线程特定的驱动程序。此外,您还有一个用于驱动程序退出方法的关闭挂钩,以及在 aftermethod 中的退出调用。 aftermethod 也可以去掉。

标签: java multithreading selenium-webdriver testng


【解决方案1】:

问题出在您的测试类 TestPlatform 中,您将 webdriver 实例变量保存到类级数据成员 WebDriver webDriver

因此,当两个或多个 @Test 方法并行运行时,所有这些方法实际上都在尝试将 webdriver 实例分配给同一个 webDriver 实例。

请按如下方式修复。

class TestPlatform {

    @BeforeMethod
    void startUpWebBrowser(){
        DriverFactory.createStackWebDriver()
        //Access webdriver instances only via DriverFactory.createStackWebDriver()
    }

    @AfterMethod
    void quitWebDriver(){
        DriverFactory.createStackWebDriver().quit()
    }
}

【讨论】:

    【解决方案2】:

    看起来像 ThreadLocal 滥用。我会使用以下 sn-p:

    private static final ThreadLocal<WebDriver> DRIVER_CONTAINER = new ThreadLocal<>();
    
    @BeforeMethod
    void startUpWebBrowser(){
        DRIVER_CONTAINER.set(createWebDriver());
    }
    
    @AfterMethod
    void quitWebDriver(){
        ofNullable(getDriver()).ifPresent(WebDriver::quit);
        DRIVER_CONTAINER.remove();
    }
    
    public static WebDriver getDriver() {
        return DRIVER_CONTAINER.get();
    }
    

    或者只是将驱动管理部分移到IInvokedMethodListener

    【讨论】:

      猜你喜欢
      • 2012-09-06
      • 1970-01-01
      • 2021-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-01
      • 2022-01-23
      • 2016-09-17
      相关资源
      最近更新 更多