【问题标题】:Can ThreadLocal be used in Cucumber paralel tests using mvn surefire plugin可以使用 maven surefire 插件在 Cucumber 并行测试中使用 ThreadLocal
【发布时间】:2021-11-17 17:40:47
【问题描述】:

在我们的 e2e 项目中,我们希望并行执行测试场景。在少数地方,我们希望每个线程存储一些东西,例如WebDriver、场景特定状态等。我的第一种方法是使用 ThreadLocal,例如:

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

但也要记住使用 ThreadLocal 和线程池组合的问题(例如这里提到的 here)我想知道 ThreadLocal 是否真的可以在这种情况下使用。

我不知道 cucumber 或 surefire 实现细节的见解,所以我不知道这种设置是否是线程安全的,因为我没有完全控制这些线程如何产生以及如何被拆除,这意味着我可以'不在适当的时候清理 ThreadLocal。

【问题讨论】:

  • ThreadLocals 和池没有“问题”。使用池时-您只需要手动进行清理,因为这仅用于测试,老实说,谁在乎您是否不及时清理它们?测试完成后,它们将被销毁并进行清理无论如何
  • 我建议在使用ThreadLocal时不要使用hooks
  • @Eugene 据我所知,当 cucumber 决定重用池中已经用于不同场景的线程时,可能会出现问题。然后可以将一些线程相关的数据与之关联。但现在我在想,如果我们在一个黄瓜钩子中清理所有与线程相关的数据,它应该可以正常工作。
  • @NandanA 背后有什么原因吗?

标签: java multithreading cucumber maven-surefire-plugin


【解决方案1】:

我将courgette-jvmcucumber-guice 结合使用以在没有ThreadLocal 的情况下并行化测试。它将小黄瓜中的场景特定信息输入到 ui 中,不需要任何 ThreadLocalpool 。它也不需要你清洁任何东西。此设置会自动为每个场景创建单独的 webdriver 实例并并行运行单独的浏览器。我将它与 selenium hub 一起使用,并在需要时将其扩展到 docker

import courgette.api.CourgetteOptions;
import courgette.api.CourgetteRunLevel;
import courgette.api.CucumberOptions;
import courgette.api.testng.TestNGCourgette;
import org.testng.annotations.Test;

@Test
@CourgetteOptions(
        threads = 10,
        runLevel = CourgetteRunLevel.SCENARIO,
        rerunFailedScenarios = true,
        rerunAttempts = 1,
        showTestOutput = true,
        reportTitle = "Courgette-JVM Example",
        reportTargetDir = "build",
        environmentInfo = "browser=chrome; git_branch=master",
        cucumberOptions = @CucumberOptions(
                features = "src/test/resources/com/test/",
                glue = "com.test.stepdefs",
                //tags = {"@post or @get"},
                publish = true,
                plugin = {
                        "pretty",
                        "json:target/cucumber-report/cucumber.json",
                        "html:target/cucumber-report/cucumber.html"}
        ))
class AcceptanceIT extends TestNGCourgette {
}

相关的pom元素

</dependency>
      <dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>6.14.3</version>
    <scope>test</scope>
</dependency>
      <dependency>
    <groupId>io.cucumber</groupId>
    <artifactId>cucumber-testng</artifactId>
    <version>6.9.1</version>
</dependency>
      <dependency>
    <groupId>io.github.prashant-ramcharan</groupId>
    <artifactId>courgette-jvm</artifactId>
    <version>5.11.0</version>
</dependency>
      <dependency>
  <!-- httpclient dpendendecy is to resolve courgette-jvm error -  NoClassDefFoundError: org/apache/http/conn/ssl/TrustAllStrategy -->        
 <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.10</version>
</dependency>

RemoteWebdriver 配置

protected RemoteWebDriver createDriver() throws MalformedURLException {
       
        String hubURL = 
            "http://192.168.1.3:"+"selenium hub port here"+"/wd/hub";
             ChromeOptions options = new ChromeOptions();
             DesiredCapabilities capabilities = DesiredCapabilities.chrome();
             capabilities.setCapability(ChromeOptions.CAPABILITY, options);
             return (RemoteWebDriver) (driver = new RemoteWebDriver(new URL(hubURL), capabilities));

        }

        @Override
         public RemoteWebDriver getDriver() throws MalformedURLException {
                this.createDriver();
                return (RemoteWebDriver) driver;
        }

cucumber-guice 相关配置

    import io.cucumber.guice.ScenarioScoped;    
    @ScenarioScoped
          public class Global {
          public RemoteWebDriver driver;
           
          public Global() throws MalformedURLException, IOException {
                driver = new DriverFactory().getManager();
               // getManager() should have driver from above createDriver()

          }
    }

在您的 stepdefs 中注入 Global 类,如下所示(进行必要的导入)。您也可以注入辅助类,guice 将在每个场景中提供它

 @Inject
   Global global;
 
  //then you can do
   global.driver.get(site);

黄瓜酱的 pom

 <dependency>
      <groupId>io.cucumber</groupId>
      <artifactId>cucumber-guice</artifactId>
      <version>${cucumber.version}</version>
      <scope>test</scope>
    </dependency>

【讨论】:

  • 感谢您的回答,这是一种有价值的方法。不过,我认为我们现在不会做出这样的改变。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-10
  • 2014-01-07
  • 1970-01-01
  • 2021-05-16
  • 1970-01-01
  • 2020-09-29
  • 2015-12-28
相关资源
最近更新 更多