java 并行运行Selenium测试(使用ThreadLocal)会打开孤立的浏览器

tyg4sfes  于 2023-01-01  发布在  Java
关注(0)|答案(2)|浏览(159)

我使用ThreadLocal来保证线程安全,并使用Maven故障安全和JUnit并行运行测试。我正在运行来自两个特性文件的两个测试来测试并行运行。
但是我总是第一个浏览器是空白的,然后后面的浏览器都很好,测试也通过了,如果我按顺序运行,就没有问题了。

  • 钩步 * 类:
public class HookStep {

        @Before()
        public void beginTest() {
            WebDriverFactory.setDriver(Props.getValue("browser.name"));
        }

        @After()
        public void stopTest(Scenario scenario) {
            switch (environment) {

                case "local":
                case "aws": {
                    if (scenario.isFailed()) {
                        Screenshots.Shot shot = new Screenshots(Screenshots.CONTEXT_TEST_FAIL)
                                .takeShot(scenario.getName() + formCounter.getAndIncrement() + "");
                        scenario.embed(shot.getContent(), "image/png", "Error - ");
                    }
                    WebDriverFactory.closeBrowser();
                }
            }
}

Web驱动程序工厂类:

public class WebDriverFactory {

    private static ThreadLocal<WebDriver> driver = new ThreadLocal<>();

    public static synchronized void setDriver(String browser) {

        switch (browser) {
            case "chrome":
                driver = ThreadLocal.withInitial(() -> {
                    WebDriverManager.chromedriver().setup();
                    return new ChromeDriver(BrowserOptions.getChromeOptions());
                });
                prepareBrowser();
                break;

            case "fireFox":
                driver = ThreadLocal.withInitial(() -> {
                    WebDriverManager.firefoxdriver().setup();
                    return new FirefoxDriver(BrowserOptions.getFirefoxOptions());
                });
                break;
            default:
                throw new IllegalStateException("Unexpected value: " + browser);
        }
    }

    private static void prepareBrowser() {
        getDriver().manage().window().maximize();
        getDriver().manage().deleteAllCookies();
        getDriver().manage().timeouts().pageLoadTimeout(15, TimeUnit.SECONDS);
        getDriver().manage().timeouts().implicitlyWait(2, TimeUnit.SECONDS);
    }

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

    public static void closeBrowser() {

        getDriver().quit();
    }
}

StepDef类:

public class SampleStepDef {
    private final WorldHelper helper;

    public SampleStepDef(WorldHelper helper) {
        this.helper = helper;
    }

    @Given("I click on the URL")
    public void iClickOnTheURL() {

       helper.getSamplePage().navigateToSite();
    }
}

public class WorldHelper {
    WebDriverFactory webDriverFactory = new WebDriverFactory();

    protected  WebDriver webDriver = webDriverFactory.getDriver();
    private  BasePage basePage;
    private  SamplePage samplePage;

    public SamplePage getSamplePage() {
        if(samplePage != null)
            return samplePage;
        samplePage = PageFactory.initElements(webDriver, SamplePage.class);
        return samplePage;
    }

}

public class SamplePage extends BasePage {

    public SamplePage(WebDriver webDriver) {
        super(webDriver);
    }

    public void navigateToSite() {

        webDriver.get("https://www.bbc.co.uk");
        webDriver.findElement(By.xpath("//a[contains(text(),\'News\')]")).click();
    }
}

public class BasePage extends WorldHelper {

    public BasePage(WebDriver driver) {
        this.webDriver = driver;
    }
}

如何解决此问题?

r6hnlfcb

r6hnlfcb1#

我注意到与您的代码相关的多个问题。
1.您正在使用ThreadLocal.withInitial()。理想情况下,它应该在示例化driver线程局部静态变量时定义。
所以与其说

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

本来应该是

private static final ThreadLocal<WebDriver> driver = ThreadLocal.withInitial(() -> {
    return null; //Your supplier goes here.
});

1.您的继承层次结构中有一个明显的混乱(很有可能您试图创建一个简单的示例,并且可能忽略了继承层背后的细节),但是不清楚为什么您的所有页面对象类都扩展WorldHelper
1.您在类级别上有多个语句,如以下所示。这些字段级别初始化的问题在于,它们在构造对象时被调用。因此,如果对象是在不同的线程中构造的,则您会遇到为该线程触发WebDriver初始化的问题。最终结果:您有许多ghost浏览器示例不断打开,但没有针对它们的selenium操作。

private final WebDriver driver = WebDriverFactory.getDriver();

当使用WebDriver管理的ThreadLocal变体时,您需要确保您的调用总是来自您的步骤定义,而不是来自构造函数或来自如上所述的类级字段初始化。
下面是您需要执行的修复列表。
1.删除代码中出现的所有private final WebDriver driver = WebDriverFactory.getDriver();。它们不再需要。
1.将WebDriverFactory类重构为如下所示(为了简洁起见,我删除了所有注解掉的代码)

public class WebDriverFactory {

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

     public static void setDriver(String browser) {
         RemoteWebDriver rwd;
             switch (browser) {
             case "chrome":
                 WebDriverManager.chromedriver().setup();
                 rwd = new ChromeDriver(BrowserOptions.getChromeOptions());
                 break;

             case "fireFox":
                 WebDriverManager.firefoxdriver().setup();
                 rwd = new FirefoxDriver(BrowserOptions.getFirefoxOptions());
                 break;
             default:
                 throw new IllegalStateException("Unexpected value: " + browser);
         }
         driver.set(Objects.requireNonNull(rwd));
         prepareBrowser();
     }

     private static void prepareBrowser(){
         getDriver().manage().window().maximize();
         getDriver().manage().deleteAllCookies();
         getDriver().manage().timeouts().pageLoadTimeout(15, TimeUnit.SECONDS);
         getDriver().manage().timeouts().implicitlyWait(2, TimeUnit.SECONDS);
     }

     public static WebDriver getDriver(){
         return Objects.requireNonNull(driver.get());
     }

     public static void closeBrowser() {
         getDriver().manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
         getDriver().close();
         getDriver().quit();
     }
 }

1.由于所有页面类似乎都是从WorldHelper扩展而来的,因此在其中添加一个getter方法,如下所示(或者)确保在任何页面类中没有WebDriver字段。无论何时需要获取WebDriver示例,你应该直接通过WebDriverFactory.getDriver()(或者)通过getter方法来完成,比如在你的WorldHelper或者你正在创建的任何基类中。

protected WebDriver getDriver() {
     return WebDriverFactory.getDriver();
 }

一旦你解决了上述问题,你应该很好,不应该看到任何空白的浏览器窗口打开。
注意:请清理你在GitHub上的项目。我注意到其中有一些云服务提供商的凭据(可能是真的凭据,也可能是假的。我不知道。)

nhhxz33t

nhhxz33t2#

我没有使用过webDriverFactory,但我会尝试在工厂类中调用driver.set(),如本教程所示:
http://makeseleniumeasy.com/2020/05/27/threadlocal-static-webdriver-for-parallel-execution/

相关问题