依赖注入在 Cucumber 项目中初始化 driver 并使用钩子而不终止 session

Dependence injection to initialize driver in cucumber project and use hook without terminating session

我正在尝试使用 Page Object 模型实现 Cucumber,我遇到了几个问题并且有很多问题。

  1. 我的 iOS 应用程序并没有那么复杂,但我仍然想组织所有 stepdef 和功能以与 POM 中的页面相对应。所以我会有多个 stepdef 和 运行ners。组织所有这些的最佳做法是什么?我尝试了 Pico DI,但甚至无法通过它传递我的 driver 实例。(如果可以,请提供结构解决方案)

  2. 因为它s native iOS - I我不会在每个场景后关闭应用程序(这需要永远)。但我仍然希望 re-usability 保持功能干燥 创建一个 appium driver 实例并且在执行功能之前永远不会创建另一个实例的最佳方法是什么?我知道我只需要在最后一步添加 driver.quit。我正在纠结的是在所有项目(Pages,Stepdefs)中使用相同的 driver(见代码)

  3. 我打算 运行 使用 TestNg 进行测试,想知道 @Before @After 注释是否仍然适用于 stepdefs 还是最好避免使用它们?

  4. 主要问题:使用 pico 进行依赖注入。由于我所有的测试都是验收(端到端功能测试),我想知道创建一个包含我所有页面的 InjectionSetUp class 和 driver

    [=48= 是否是个好主意]

Driver经理

public class IOSDriverManager {
    public static ThreadLocal<IOSDriver<IOSElement>> webDriver = new ThreadLocal<IOSDriver<IOSElement>>();

 public static DesiredCapabilities getIOSCapsLocal() {
        DesiredCapabilities caps = new DesiredCapabilities();
         //My caps
  return caps;

 public static void createThreadLocalWebDriver() {
        IOSDriver<IOSElement> driver = null;
//try catch
      driver = new IOSDriver<IOSElement>(new URL(APPIUM_SERVER_URL), getIOSCapsLocal());
//try catch
        webDriver.set(driver);
 }
 public static IOSDriver<IOSElement> getThreadLocalDriver() {
        IOSDriver<IOSElement> driver = webDriver.get();
        if (driver == null) {
            createThreadLocalWebDriver();
            driver = webDriver.get();
        }
        return driver;
    }

BasePage

public class BasePage {
    IOSDriver<IOSElement> Driver;
    public BasePage(IOSDriver<IOSElement> driver) {
     initElements();
     Driver = driver;
    }

    private void initElements() {

        PageFactory.initElements(new AppiumFieldDecorator(getDriver()),this);
    }

    protected IOSDriver<IOSElement> getDriver() {
        return IOSDriverManager.getThreadLocalDriver();
    }

}

任何页面

public class BiosurveyPage extends BasePage {
 public BiosurveyPage(IOSDriver<IOSElement> driver) {
        super(driver); //  Appiumfield  decorator is applied by BasePage constructor
//Is it better to just use getDriver() method throughout all pages instead of declaring driver again ? 
    }

最后 StepDefs

public class newSignUpFlowTest{
    protected IOSDriver<IOSElement> getDriver() {
        return IOSDriverManager.getThreadLocalDriver();
    }
    LoginPage poLogin = new LoginPage(getDriver());
    SignUpPage poSignup = new SignUpPage(getDriver());
      // 10+ pages 

@Given("I am on Login Page")
    public void iAmOnLoginPage() {
        assertThat("ON LOGIN PAGE",poLogin.isLoginScreen(),equalTo(true));
    }

    @When("I tap on Sign Up Link")
    public void iTapsOnSignUpLink() {
        poLogin.clickSignUp();
    }
// 20+ methods for this feature

更新 我修复了所有问题并能够进行 运行 测试。现在我的问题是——我的框架看起来不错吗?我不知道t have any real life experience prior to this. So can someone just approve me and suggest enhancements to keep up with best industry practices ? I know this post might piss some people off, but i don不知道还有什么地方可以交流这个,因为我在 QA 领域没有任何朋友,也没有远程工作

使用依赖注入时,您希望让 DI 系统完成所有繁重的工作。因此,您的步骤定义对您的页面对象具有构造函数依赖性。

public class NewSignUpFlowStepDefinitions {

    private final LoginPage poLogin;
    private final SignUpPage poSignup;

    NewSignUpFlowStepDefinitions(LoginPage poLogin, SignUpPage poSignup) {
        this.poLogin = poLogin;
        this.poSignup = poSignup;
    }

    @Given("I am on Login Page")
    public void iAmOnLoginPage() {
        assertThat("ON LOGIN PAGE", poLogin.isLoginScreen(), equalTo(true));
    }

    @When("I tap on Sign Up Link")
    public void iTapsOnSignUpLink() {
        poLogin.clickSignUp();
    }

}

您的页面对象不能对 IOSDriver<IOSElement> 有构造函数依赖,因为 PicoContainer 只能创建不以空构造函数结尾的依赖链。所以我们在这里使用 IOSDriverManager

public class BiosurveyPage extends BasePage {
    public BiosurveyPage(IOSDriverManager driverManager) {
        super(driverManager);
    }
}

然后在您的 BasePage 中从驱动程序管理器中解压 webdriver。

public abstract class BasePage {
    private IOSDriverManager driverManager;

    public BasePage(IOSDriverManager driverManager) {
        this.driverManager = driverManager;
        initElements();
    }

    private void initElements() {
        PageFactory.initElements(new AppiumFieldDecorator(driverManager.getDriver()), this);
    }

    protected IOSDriver<IOSElement> getDriver() {
        return driverManager.getDriver();

    }
}

然后在 IOSDriverManager 中您可以保留对 webdriver 的引用并根据需要创建它。如果您确定在场景之间共享您的网络驱动程序是安全的,您仍然可以在此处使用 ThreadLocal

public class IOSDriverManager implements Disposable{
    private IOSDriver<IOSElement> webDriver;

    private DesiredCapabilities getIOSCapsLocal() {
        DesiredCapabilities caps = new DesiredCapabilities();
        return caps;
    }

    private void createWebDriver() {
        webDriver = new IOSDriver<IOSElement>(new URL(APPIUM_SERVER_URL), getIOSCapsLocal());
    }

    public IOSDriver<IOSElement> getDriver() {
        if (webDriver == null) {
            createThreadLocalWebDriver();
        }
        return webDriver;
    }

    @Override
    public void dispose() {
        // Stop webdriver ehre
    }
}

请注意,Disposable 添加了 dispose 方法,可以让您在每个场景后清理驱动程序。要么完全处置它,要么将其重置为某个已知状态。

http://picocontainer.com/lifecycle.html