问题
I have a design issue when I am trying to build a framework using cucumber, selenium and cucumber-spring. My expected behavior is to quit WebdDriver instance for every scenario. But
Here is my page objects in 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;
}
}
Here is another page object class which extends the Base class.
@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();
}
}
The webdriver is created with Factory Design pattern. Based on the browser mentioned in the properties file it will create the desired webdriver instance. And these Driver classes are not created with @Component
And spring configuration class under src/test/java
as shown below.
@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;
}
}
This is the step definitions class under 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;
}
}
}
Here is my actual problem in the Step Definitions. For every Test Scenario If I call driver.quit()
the remaining test scenarios will be failed with the below exception because the bean WebDriver killed in @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)
The reason why I am getting this error is because the webdriver is closed which is an Injected bean. Is there any solution to create wedriver in @Before and kill webdriver in @After for each cucumber scenario? Is there any flaw in the design?
回答1:
Apart from the @DirtiesContext used by OP as solution . Tried using @Scope(SCOPE_CUCUMBER_GLUE)/@Scope("cucumber-glue") . Unique instance of Webdriver is created and destroyed in each scenario.
Reference
Changing a Spring bean's scope to SCOPE_CUCUMBER_GLUE will bound its lifecycle to the standard glue lifecycle.
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 {
}
Base Page:
@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;
}
}
Base Page :
@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:
@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;
}
}
Steps:
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;
// }
}
}
Note: All chromeriver background processes are killed.
来源:https://stackoverflow.com/questions/57478175/design-issue-in-cucumber-spring-webdriver-quit-in-after-method