使用cucumber、jmeter和failsafe的自动化框架是否需要threadlocal?

vdzxcuhz  于 2021-06-29  发布在  Java
关注(0)|答案(1)|浏览(437)

抱歉,如果这个问题听起来很傻。我们正在开发一个自动化框架,它将使用java、cucumber、junit和failsafe套件等。有人建议使用threadlocal。但是我有点困惑,为什么当junit在自己的线程中运行cucumber特性时我们需要使用threadlocal。。
建议使用threadlocal,如下所示-

  1. public class WebDriverFactory {
  2. private static ThreadLocal<WebDriver> driver = new ThreadLocal<>();
  3. public static synchronized void setDriver(String browser) {
  4. switch (browser) {
  5. case "chrome":
  6. driver = ThreadLocal.withInitial(() -> {
  7. WebDriverManager.chromedriver().setup();
  8. return new ChromeDriver(BrowserOptions.getChromeOptions());
  9. });
  10. break;
  11. default:
  12. throw new IllegalStateException("Unexpected value: " + browser);
  13. }
  14. }
  15. public static synchronized WebDriver getDriver(){
  16. return driver.get();
  17. }

有人能确认并行运行测试是否真的需要这样做吗。?另外,使用threadlocal时是否需要“synchronized”?

gorkyyrv

gorkyyrv1#

视情况而定。
当使用静态字段时,jvm中只有该字段的一个示例。它指的是内存中的一个特定地址。与对象的字段不同,对象的字段引用特定对象的字段,并且对于每个对象,该字段在内存中有一个唯一的地址。
当使用 ThreadLocal 每个线程都有自己的变量示例。
所以通过使用 static WebDriver driver 对于所有测试和所有线程,您只有一个webdriver。通过使用 static ThreadLocal<WebDriver> driver 每个线程只有一个webdriver,在该线程上执行的场景之间有效地共享webdriver。
当并行执行测试时,有多个线程在执行场景,因此单个webdriver将是一个问题。并行运行的场景将使webdriver同时执行不同的操作,或者它们必须等待webdriver可用,从而使它们再次有效地串行运行。
因此,如果要在场景之间共享一个webdriver,并且如果这些场景并行运行,则必须使用 ThreadLocal .
然而,我们似乎不熟悉并发系统的编程。因此,您可能需要考虑另一种方法。与其在场景之间共享webdriver,不如考虑在每个场景中启动一个新的webdriver。这更安全,从测试的Angular 看也更干净,因为每个场景开始时都没有前一个场景中的任何状态。
这意味着您现在遇到了在步骤之间共享信息的问题。您使用了一个静态字段来共享webdriver。但是不能使用静态字段,因为现在有多个线程正在运行。
为了解决这个问题,cumber支持依赖注入。最容易使用的可能是 cucumber 皮。当使用依赖注入时,cumber将用一组独立的依赖项为每个场景示例化每个步骤定义类。

  1. <dependency>
  2. <groupId>io.cucumber</groupId>
  3. <artifactId>cucumber-picocontainer</artifactId>
  4. <version>${cucumber.version}</version>
  5. <scope>test</scope>
  6. </dependency>

例如,当步骤定义依赖于 WebDriverFactory ,将示例化 WebDriverFactory 为你和示例化两者 StepDefinition 以及 OtherStepDefinition 同一家工厂。

  1. public class StepDefinition {
  2. private final WebDriverFactory webdriverFactory;
  3. public StepDefinitions(WebDriverFactory webdriverFactory) {
  4. this.webdriverFactory = webdriverFactory;
  5. }
  6. @Given("I do a thing with a webdriver")
  7. public void useTheWebDriver() {
  8. // get the webdriver from the factory and use it
  9. }
  10. }
  11. public class OtherStepDefinition {
  12. private final WebDriverFactory webdriverFactory; // Same instance as in StepDefinition
  13. public OtherStepDefinition(WebDriverFactory webdriverFactory) {
  14. this.webdriverFactory = webdriverFactory;
  15. }
  16. @Given("I do another thing with a webdriver")
  17. public void useTheWebDriver() {
  18. // get the webdriver from the factory and use it
  19. }
  20. }

然后在web驱动程序工厂中,您保留对webdriver的引用,以便在两个步骤定义中使用。

  1. public class WebDriverFactory implements Startable {
  2. private WebDriver driver;
  3. public setDriver(String browser) {
  4. // create the web driver here
  5. }
  6. public static synchronized WebDriver getDriver(){
  7. return driver;
  8. }
  9. public void start() {
  10. // do nothing
  11. }
  12. public void stop() {
  13. // stop web driver if it was created
  14. }
  15. }
展开查看全部

相关问题