使用 Cucumber、Jmeter 和 FailSafe 的自动化框架是否需要 ThreadLocal?
Is ThreadLocal required for automation framework that uses Cucumber, Jmeter and FailSafe?
抱歉,如果这个问题听起来很傻。
我们正在开发一个自动化框架,该框架将使用 Java、Cucumber、Junit 和 Failsafe 套件等。
有人建议使用 ThreadLocal。但是我有点困惑,为什么我们需要在 Junit 运行 在其自己的线程中使用黄瓜功能时使用 ThreadLocal..
建议使用 ThreadLocal,如下所示;-
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());
});
break;
default:
throw new IllegalStateException("Unexpected value: " + browser);
}
}
public static synchronized WebDriver getDriver(){
return driver.get();
}
任何人都可以确认这是否真的需要 运行 并行测试。?另外,使用 ThreadLocal 时是否需要 'synchronized'?
视情况而定。
使用静态字段时,JVM 中只有该字段的一个实例。它指的是内存中的一个特定地址。与引用特定对象字段的对象字段不同,对于每个对象,该字段在内存中都有一个唯一地址。
当使用 ThreadLocal
时,每个线程都有自己的变量实例。
因此,通过使用 static WebDriver driver
,您就拥有了一个用于所有测试和所有线程的网络驱动程序。通过使用 static ThreadLocal<WebDriver> driver
,每个线程只有一个 webdriver,有效地在该线程上执行的场景之间共享 webdriver。
当并行执行测试时,有多个线程执行场景,因此单个 webdriver 会成为问题。场景 运行 并行会使 webdriver 同时做不同的事情,或者他们必须等待 webdriver 可用,使它们再次有效地 运行 串行。
因此,如果要在场景之间共享网络驱动程序,并且如果这些场景 运行 并行,则必须使用 ThreadLocal
.
不过看来对并发系统编程不熟悉。因此,您可能需要考虑一种不同的方法。与其在场景之间共享 webdriver,不如考虑在每个场景中启动一个新的 webdriver。这更安全,从测试的角度来看也更清晰,因为每个场景都在没有前一个场景的任何状态的情况下开始。
这意味着您现在遇到了步骤之间共享信息的问题。您使用静态字段来共享网络驱动程序。但是你不能使用静态字段因为现在有多个线程运行ning.
解决这个问题 Cucumber支持依赖注入。最容易使用的可能是 cucumber-pico。当使用依赖注入时,Cucumber 将为每个场景实例化每个步骤定义 class,并具有一组独立的依赖项。
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-picocontainer</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
因此,例如,当您的步骤定义依赖于 WebDriverFactory
时,cucumber 将为您实例化一个 WebDriverFactory
,并使用同一个工厂实例化 StepDefinition
和 OtherStepDefinition
.
public class StepDefinition {
private final WebDriverFactory webdriverFactory;
public StepDefinitions(WebDriverFactory webdriverFactory) {
this.webdriverFactory = webdriverFactory;
}
@Given("I do a thing with a webdriver")
public void useTheWebDriver() {
// get the webdriver from the factory and use it
}
}
public class OtherStepDefinition {
private final WebDriverFactory webdriverFactory; // Same instance as in StepDefinition
public OtherStepDefinition(WebDriverFactory webdriverFactory) {
this.webdriverFactory = webdriverFactory;
}
@Given("I do another thing with a webdriver")
public void useTheWebDriver() {
// get the webdriver from the factory and use it
}
}
然后在网络驱动程序工厂中,您保留对网络驱动程序的引用以用于两个步骤定义。
public class WebDriverFactory implements Startable {
private WebDriver driver;
public setDriver(String browser) {
// create the web driver here
}
public static synchronized WebDriver getDriver(){
return driver;
}
public void start() {
// do nothing
}
public void stop() {
// stop web driver if it was created
}
}
抱歉,如果这个问题听起来很傻。 我们正在开发一个自动化框架,该框架将使用 Java、Cucumber、Junit 和 Failsafe 套件等。 有人建议使用 ThreadLocal。但是我有点困惑,为什么我们需要在 Junit 运行 在其自己的线程中使用黄瓜功能时使用 ThreadLocal..
建议使用 ThreadLocal,如下所示;-
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());
});
break;
default:
throw new IllegalStateException("Unexpected value: " + browser);
}
}
public static synchronized WebDriver getDriver(){
return driver.get();
}
任何人都可以确认这是否真的需要 运行 并行测试。?另外,使用 ThreadLocal 时是否需要 'synchronized'?
视情况而定。
使用静态字段时,JVM 中只有该字段的一个实例。它指的是内存中的一个特定地址。与引用特定对象字段的对象字段不同,对于每个对象,该字段在内存中都有一个唯一地址。
当使用 ThreadLocal
时,每个线程都有自己的变量实例。
因此,通过使用 static WebDriver driver
,您就拥有了一个用于所有测试和所有线程的网络驱动程序。通过使用 static ThreadLocal<WebDriver> driver
,每个线程只有一个 webdriver,有效地在该线程上执行的场景之间共享 webdriver。
当并行执行测试时,有多个线程执行场景,因此单个 webdriver 会成为问题。场景 运行 并行会使 webdriver 同时做不同的事情,或者他们必须等待 webdriver 可用,使它们再次有效地 运行 串行。
因此,如果要在场景之间共享网络驱动程序,并且如果这些场景 运行 并行,则必须使用 ThreadLocal
.
不过看来对并发系统编程不熟悉。因此,您可能需要考虑一种不同的方法。与其在场景之间共享 webdriver,不如考虑在每个场景中启动一个新的 webdriver。这更安全,从测试的角度来看也更清晰,因为每个场景都在没有前一个场景的任何状态的情况下开始。
这意味着您现在遇到了步骤之间共享信息的问题。您使用静态字段来共享网络驱动程序。但是你不能使用静态字段因为现在有多个线程运行ning.
解决这个问题 Cucumber支持依赖注入。最容易使用的可能是 cucumber-pico。当使用依赖注入时,Cucumber 将为每个场景实例化每个步骤定义 class,并具有一组独立的依赖项。
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-picocontainer</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
因此,例如,当您的步骤定义依赖于 WebDriverFactory
时,cucumber 将为您实例化一个 WebDriverFactory
,并使用同一个工厂实例化 StepDefinition
和 OtherStepDefinition
.
public class StepDefinition {
private final WebDriverFactory webdriverFactory;
public StepDefinitions(WebDriverFactory webdriverFactory) {
this.webdriverFactory = webdriverFactory;
}
@Given("I do a thing with a webdriver")
public void useTheWebDriver() {
// get the webdriver from the factory and use it
}
}
public class OtherStepDefinition {
private final WebDriverFactory webdriverFactory; // Same instance as in StepDefinition
public OtherStepDefinition(WebDriverFactory webdriverFactory) {
this.webdriverFactory = webdriverFactory;
}
@Given("I do another thing with a webdriver")
public void useTheWebDriver() {
// get the webdriver from the factory and use it
}
}
然后在网络驱动程序工厂中,您保留对网络驱动程序的引用以用于两个步骤定义。
public class WebDriverFactory implements Startable {
private WebDriver driver;
public setDriver(String browser) {
// create the web driver here
}
public static synchronized WebDriver getDriver(){
return driver;
}
public void start() {
// do nothing
}
public void stop() {
// stop web driver if it was created
}
}