【问题标题】:Design issue in Cucumber spring WebDriver quit in @After methodCucumber spring WebDriver中的设计问题在@After方法中退出
【发布时间】:2019-08-13 12:54:09
【问题描述】:

我在尝试使用 cucumber、selenium 和 cucumber-spring 构建框架时遇到了设计问题。我的预期行为是为每个场景退出 WebdDriver 实例。但是

这是我在src\main\java中的页面对象

@Component
public class BasePage {
WebDriver driver;
 public BasePage(WebDriver driver) {
    this.driver = driver;
    PageFactory.initElements(driver, this);

 }
 public WebDriver getDriver() {
    return this.driver;
  }

}

这是另一个扩展 Base 类的页面对象类。

@Component
public class LoginPage extends BasePage
{
public LoginPage(WebDriver webDriver) {
    super(webDriver);
}

@FindBy(xpath = "/html/body/app-root/s-login-pg/div/form/input[1]")
WebElement loginTextBox;

@FindBy(xpath = "/html/body/app-root/s-login-pg/div/form/input[2]")
WebElement passwordTextBox;

@FindBy(xpath="/html/body/app-root/s-login-pg/div/form/button")
WebElement loginButton;

public void openApplication(String url){
    driver.get(url);
    waitForPageToLoad();
}

public void inputUsername(String username){
    loginTextBox.sendKeys(username);
}

public void inputPassword(String password){
    loginTextBox.sendKeys(password);
}

public void clickLoginButton(){
    loginButton.click();
 }
}

webdriver 是使用工厂设计模式创建的。根据属性文件中提到的浏览器,它将创建所需的 webdriver 实例。而且这些Driver类不是用@Component创建的

src/test/java下的spring配置类如下图。

@Configuration
@ContextConfiguration(classes={PropertiesContext.class})
@ComponentScan(basePackages = "com.company.project")
public class CucumberContext {

@Autowired
private String browser;

  @Bean(name = "webdriver", destroyMethod = "quit")
  public WebDriver getWebDriver() {
    WebDriver webdriver = null;
    webdriver = DriverManagerFactory.getManager(browser).getDriver();
    return webdriver;
  }
}

这是src\test\java下的步骤定义类

public class StepDefinitions extends ParentSteps {

@Autowired
private LoginPage loginPage;

@Autowired
private HomePage homePage;

@Before
public void init() {
    if (System.getProperty("environment") == null) {
        System.setProperty("environment", "DEV");
    }
}

@After
public void tearDown(Scenario scenario) {
    if(loginPage.getDriver() != null) {
        loginPage.getDriver().quit;
    }
}

}

这是我在步骤定义中的实际问题。对于每个测试场景如果我调用driver.quit(),剩余的测试场景将失败并出现以下异常,因为 bean WebDriver 在@After 中被杀死

org.openqa.selenium.NoSuchSessionException: Session ID is null. Using WebDriver after calling quit()?
Build info: version: '3.14.0', revision: 'aacccce0', time: '2018-08-02T20:19:58.91Z'
Driver info: driver.version: RemoteWebDriver

at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:125)
at org.openqa.selenium.remote.service.DriverCommandExecutor.execute(DriverCommandExecutor.java:83)
at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:548)

我收到此错误的原因是 webdriver 已关闭,它是一个 Injected bean。对于每个黄瓜场景,是否有任何解决方案可以在 @Before 中创建 wedriver 并在 @After 中杀死 webdriver?设计有什么缺陷吗?

【问题讨论】:

  • 您是按顺序运行场景还是并行运行场景?黄瓜是什么版本的?
  • 我正在按顺序运行场景。我也尝试过并行但没有奏效。我正在使用最新版本1.2.5
  • 在@After 中退出驱动程序有什么具体原因吗?您将不得不在 cucumber-spring 中找到等效的解决方案。类似于 cucumber-guice static.javadoc.io/info.cukes/cucumber-guice/1.2.5/index.html中的“@ScenarioScoped”的东西@
  • @DirtiesContext 可以工作,但是测试非常慢,因为每次测试都需要花费大量时间来加载上下文
  • @vkrams 在所有组件 (Pages) + @Bean(name = "webdriver") 上使用 @Scope("cucumber-glue") 尝试了上面的示例。正常工作,没有观察到缓慢。

标签: java spring selenium selenium-webdriver cucumber


【解决方案1】:

除了 OP 使用的 @DirtiesContext 作为解决方案。尝试使用 @Scope(SCOPE_CUCUMBER_GLUE)/@Scope("cucumber-glue") 。在每个场景中创建和销毁 Webdriver 的唯一实例。

Reference

将 Spring bean 的范围更改为 SCOPE_CUCUMBER_GLUE 会将其生命周期绑定到标准胶水生命周期。

import org.springframework.stereotype.Component;
import org.springframework.context.annotation.Scope;
import static io.cucumber.spring.CucumberTestContext.SCOPE_CUCUMBER_GLUE;

@Component
@Scope(SCOPE_CUCUMBER_GLUE)
public class MyComponent {
}

基本页面:

@Component
@Scope("cucumber-glue")
public class BasePage {
WebDriver driver;
 public BasePage(WebDriver driver) {
    this.driver = driver;
    PageFactory.initElements(driver, this);

 }
 public WebDriver getDriver() {
    return this.driver;
  }

}

基本页面:

@Component
@Scope("cucumber-glue")
public class LoginPage extends BasePage
{
public LoginPage(WebDriver webDriver) {
    super(webDriver);
}

@FindBy(xpath = "/html/body/app-root/s-login-pg/div/form/input[1]")
WebElement loginTextBox;

@FindBy(xpath = "/html/body/app-root/s-login-pg/div/form/input[2]")
WebElement passwordTextBox;

@FindBy(xpath="/html/body/app-root/s-login-pg/div/form/button")
WebElement loginButton;

public void openApplication(String url){
    driver.get(url);
   // waitForPageToLoad();
}

public void inputUsername(String username){
    loginTextBox.sendKeys(username);
}

public void inputPassword(String password){
    loginTextBox.sendKeys(password);
}

public void clickLoginButton(){
    loginButton.click();
 }
}

配置:

@Configuration
// Not define in example so commented @ContextConfiguration(classes= 
//{PropertiesContext.class})
@ComponentScan(basePackages = "com.company.project")
public class CucumberContext {

@Autowired
private String browser;

  @Bean(name = "webdriver", destroyMethod = "quit")
  @Scope("cucumber-glue")
  public WebDriver getWebDriver() {
      WebDriver webdriver = null;
      // Removed the factory initialization code. Used simple ChromeDriver
      webdriver = new ChromeDriver();
      return webdriver;
  }
}

步骤:

public class StepDefinitions extends ParentSteps {

@Autowired
private LoginPage loginPage;

@Autowired
private HomePage homePage;

@Before
public void init() {
    if (System.getProperty("environment") == null) {
        System.setProperty("environment", "DEV");
    }
}

@After
public void tearDown(Scenario scenario) {
   // Removed quit
   // if(loginPage.getDriver() != null) {
   //     loginPage.getDriver().quit;
  //   }
}
}

注意:所有 chromeriver 后台进程都被杀死。

【讨论】:

  • 事实上,我不需要调用driver.quit() spring 上下文本身来拆除驱动程序实例。
  • 是的,我观察到了这一点。所以我在@After方法中注释了退出调用的代码
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-24
  • 2023-02-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多