Cucumber-Appium - 如果在@Before 中初始化驱动程序,则将 Hooks 存储在何处

Cucumber-Appium - Where to store Hooks if initialising driver in @Before

我将尝试解释我是如何构建它的,我想可能会跳出一些明显的东西。

我对此比较陌生,但是我正在构建一个 cucumber-appium 框架并且 运行 遇到了一些麻烦。目前,我在 @Before 挂钩中初始化我的 Appium 驱动程序,该挂钩位于包含所有挂钩的 GlobalHooks class 中。我已经更改了挂钩,所以它的一部分只在测试开始时 运行s 运行 因为 Cucumber 不支持全局挂钩而且我不明白为什么我应该在每次测试之前初始化驱动程序(我正在使用 Junit,所以无法利用 TestNG 的 @BeforeSuite 功能)。

为了利用 Appium 的并行会话,我现在想让我的驱动程序(在 GlobalHooks class 中声明并在那个 class 的 @Before 方法中定义)非静态并且它是在整个套件中呈现问题。

如果我希望我的页面 类 使用此驱动程序,那么在这样的 Hook 中定义我的驱动程序是否明智?或者有人对如何初始化非静态驱动程序有任何建议,以便它们可以用于 运行 并行 Appium 会话吗?

与 Cucumber 或 Appium 相比,这可能更像是一个 Java 问题。

这是并行使用 selenium 驱动程序的精简版本。 adopt to appium driver应该类似。这使用 pico-container 在场景中创建和共享对象。需要添加 cucumber-picocontainer 依赖。

DriverFactory 将所有驱动程序存储在一个 ThreadLocal 变量中 drivers

public final class DriverFactory {

    private static ThreadLocal<WebDriver> drivers = new ThreadLocal<>();
    //To quit the drivers and browsers at the end only. 
    private static List<WebDriver> storedDrivers = new ArrayList<>();

    static {
        Runtime.getRuntime().addShutdownHook(new Thread(){
            public void run(){
                storedDrivers.stream().forEach(WebDriver::quit);
            }
          });
    }

    private DriverFactory() {}

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

    public static void addDriver(WebDriver driver) {
        storedDrivers.add(driver);
        drivers.set(driver);
    }

    public static void removeDriver() {
        storedDrivers.remove(drivers.get());
        drivers.remove();
    }   
}

存在的唯一目的是让 pico-container 创建所需的驱动程序。检查驱动程序是否已存在以供线程重用。为避免这种情况,您可以考虑扩展 ThreadLocal class 并设置 initialValue() 方法。

public class SharedDriver {
    public SharedDriver() {
        if (DriverFactory.getDriver() == null) {
        System.setProperty("webdriver.chrome.driver", "path/to/chromedriver.exe");
        DriverFactory.addDriver(new ChromeDriver());
    }
    }   
}

public class GoogleHomePO extends LoadableComponent<GoogleHomePO>{

    @FindBy(name="q")
    private WebElement searchTextBox;

    public GoogleHomePO() {
        DriverFactory.getDriver().get("https://www.google.com/");
        PageFactory.initElements(DriverFactory.getDriver(), this);
    }

    public void enterSearch(String search) {
        searchTextBox.sendKeys(search);
    }
}

项目中任意一步定义的构造函数都需要添加SharedDriverclass。由于 Cucumber 为每个场景初始化所有步骤和挂钩 classes,如果需要,picocontainer 将实例化驱动程序对象并将其存储在 DriverFactory 中。

public class StepDefinition {

    private GoogleHomePO gmPO;

    public StepDefinition(SharedDriver driver, GoogleHomePO gmPO) {
        this.gmPO = gmPO;
    }

    @Given("Go to google page")
    public void given() {
        gmPO.get();
    }

    @When("Enter search {string}")
    public void when(String search) {
        gmPO.enterSearch(search);
    }    
}

专题文件 1

Feature: 

  Scenario: First
    Given Go to google page
    When Enter search "From Feature One"

  Scenario: First Again
    Given Go to google page
    When Enter search "From Feature One Again Again"

专题文件 2

Feature:

  Scenario: Second
    Given Go to google page
    When Enter search "From Feature Two"

POM 设置

<plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-failsafe-plugin</artifactId>
                <version>3.0.0-M3</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>integration-test</goal>
                        </goals>
                        <configuration>
                            <includes>
                                <include>**/*Runner.java</include>
                            </includes>

                            <parallel>methods</parallel>
                            <useUnlimitedThreads>true</useUnlimitedThreads>

                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>

@蚱蜢。回到你身边是因为我说过当我有适合我的设置时我会的。再次感谢您的投入,这是无价的。我按照您的建议设置了一个 SharedDriver class,但更改了一两件事以考虑到我将 运行 在不同的连接设备上设置每个线程,这意味着一个单独的 AppiumDriver 而不是一个新的WebDriver 每次。

我通过放入我的 BeforeClass 方法解决了这个问题,一个 class 来创建一个我连接的所有设备的池。然后,我的 SharedDriver 使用 AtomicIntecger 遍历它们以保留 thread-safe 并将相关驱动程序添加到工厂。

我也喜欢在第一台连接的设备上 运行ning 测试 IDE 的想法,以进行调试和快速测试。因为 BeforeClass 没有 运行 当 运行 在 IDE 中时,我的 SharedDriver class 检查这个,如果它没有 运行 那么它为第一个连接的设备添加一个 AppiumDriver,然后 运行 对其进行测试。

很抱歉延迟回来,因为我一直在研究其他项目。再次感谢您的帮助