并行执行 selenium/cucumber 测试,但所有测试都是 运行 在同一个 Chrome 实例上
Execute selenium/cucumber test in parallel, but all tests are running on the same Chrome instance
我已经用maven、spring-boot、cucumber(jvm5)、selenium等搭建了一个测试框架。
该框架在很长一段时间内(并行)正常工作,但我最近遇到了这种有线行为。当我 运行 两个并行测试时,我可以看到两个 chrome 实例已启动,但只有一个实例正确打开 URL (另一个有数据;在 url场地)。同时在 chrome 实例上执行了两个测试。 (例如在输入框中同时输入两个不同的用户名。)
欢迎任何意见。谢谢。
下面是我的 pom.xml 并行设置:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
<configuration>
<parallel>methods</parallel>
<!--<threadCount>4</threadCount>-->
<useUnlimitedThreads>true</useUnlimitedThreads>
<argLine>
-javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
-Xmx1024m -XX:MaxPermSize=256m
</argLine>
<systemPropertyVariables>
<allure.results.directory>${project.build.directory}/allure-results
</allure.results.directory>
</systemPropertyVariables>
</configuration>
....
</plugin>
这里是 运行ner class:
@RunWith(Cucumber.class)
@CucumberOptions(
strict = true,
features = {"src/test/resources/features"},
plugin = {
"pretty",
"html:target/cucumber-html-report",
"json:target/cucumber/cucumber.json",
"junit:target/cucumber/cucumber.xml",
"io.qameta.allure.cucumber5jvm.AllureCucumber5Jvm",
"rerun:target/rerun.txt"
},
glue = {"com.demo.bss.steps", "com.demo.bss.hook"},
stepNotifications = true,
monochrome = true,
tags = {"not @deprecated"})
public class CukeTest {
}
这是步骤定义:
//Globel step state class
@Component
public class GlobalStepState {
protected WebDriver driver;
protected WebDriverWait wait;
protected LoginPage loginPage;
protected CrmMainPage crmMainPage;
protected ProdCatalogMainPage prodCataPage;
@Value("${spring.url.bss}")
protected String url;
}
//Global shared stepdefs
public class GlobalStepDef implements En {
@Autowired
GlobalStepState state;
@Autowired
CukeHook cukeHook;
public GlobalStepDef() {
Before(
1,
() -> {
state.driver = cukeHook.getWebDriver();
state.wait = new WebDriverWait(state.driver, 30);
state.loginPage = new LoginPage(state.driver);
state.crmMainPage = new CrmMainPage(state.driver);
state.prodCataPage = new ProdCatalogMainPage(state.driver);
});
Given("^open COMARCH BSS login page$", () -> {
state.driver.get(state.url);
});
}
}
//normal stepdefs
public class LoginStepDefs implements En {
@Autowired
private GlobalStepState state;
public LoginStepDefs() {
When("^I login with a user \"([^\"]*)\" and \"([^\"]*)\"$", (String email, String password) -> {
state.loginPage.inputEmail.sendKeys(email);
state.loginPage.inputPassword.sendKeys(password);
state.loginPage.btnLogin.click();
});
Then("^the (.*) user name show display as (.*)$", (String type, String userName) -> {
WebElement eleUserName = type.equals("CRM") ? state.crmMainPage.strCrmUserName : state.prodCataPage.strCatalogUserName;
state.wait.until(ExpectedConditions.visibilityOf(eleUserName));
Assert.assertEquals(userName, eleUserName.getText());
});
}
}
Spring 中的组件是单例。因此,当您创建两个网络驱动程序时,您将它们分配给同一对象的同一字段。这意味着只使用了一个。
据推测,您在升级到 v5 后已经开始遇到这种行为。由于 v5 Cucumber 将在线程之间共享 spring 应用程序上下文(与所有其他 spring 测试一样)。
https://github.com/cucumber/cucumber-jvm/blob/main/CHANGELOG.md#500-rc4-2019-12-21
为确保组件不在场景之间共享,您必须使用 @ScenarioScope
对其进行注释。
我已经用maven、spring-boot、cucumber(jvm5)、selenium等搭建了一个测试框架。
该框架在很长一段时间内(并行)正常工作,但我最近遇到了这种有线行为。当我 运行 两个并行测试时,我可以看到两个 chrome 实例已启动,但只有一个实例正确打开 URL (另一个有数据;在 url场地)。同时在 chrome 实例上执行了两个测试。 (例如在输入框中同时输入两个不同的用户名。)
欢迎任何意见。谢谢。
下面是我的 pom.xml 并行设置:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M3</version>
<configuration>
<parallel>methods</parallel>
<!--<threadCount>4</threadCount>-->
<useUnlimitedThreads>true</useUnlimitedThreads>
<argLine>
-javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
-Xmx1024m -XX:MaxPermSize=256m
</argLine>
<systemPropertyVariables>
<allure.results.directory>${project.build.directory}/allure-results
</allure.results.directory>
</systemPropertyVariables>
</configuration>
....
</plugin>
这里是 运行ner class:
@RunWith(Cucumber.class)
@CucumberOptions(
strict = true,
features = {"src/test/resources/features"},
plugin = {
"pretty",
"html:target/cucumber-html-report",
"json:target/cucumber/cucumber.json",
"junit:target/cucumber/cucumber.xml",
"io.qameta.allure.cucumber5jvm.AllureCucumber5Jvm",
"rerun:target/rerun.txt"
},
glue = {"com.demo.bss.steps", "com.demo.bss.hook"},
stepNotifications = true,
monochrome = true,
tags = {"not @deprecated"})
public class CukeTest {
}
这是步骤定义:
//Globel step state class
@Component
public class GlobalStepState {
protected WebDriver driver;
protected WebDriverWait wait;
protected LoginPage loginPage;
protected CrmMainPage crmMainPage;
protected ProdCatalogMainPage prodCataPage;
@Value("${spring.url.bss}")
protected String url;
}
//Global shared stepdefs
public class GlobalStepDef implements En {
@Autowired
GlobalStepState state;
@Autowired
CukeHook cukeHook;
public GlobalStepDef() {
Before(
1,
() -> {
state.driver = cukeHook.getWebDriver();
state.wait = new WebDriverWait(state.driver, 30);
state.loginPage = new LoginPage(state.driver);
state.crmMainPage = new CrmMainPage(state.driver);
state.prodCataPage = new ProdCatalogMainPage(state.driver);
});
Given("^open COMARCH BSS login page$", () -> {
state.driver.get(state.url);
});
}
}
//normal stepdefs
public class LoginStepDefs implements En {
@Autowired
private GlobalStepState state;
public LoginStepDefs() {
When("^I login with a user \"([^\"]*)\" and \"([^\"]*)\"$", (String email, String password) -> {
state.loginPage.inputEmail.sendKeys(email);
state.loginPage.inputPassword.sendKeys(password);
state.loginPage.btnLogin.click();
});
Then("^the (.*) user name show display as (.*)$", (String type, String userName) -> {
WebElement eleUserName = type.equals("CRM") ? state.crmMainPage.strCrmUserName : state.prodCataPage.strCatalogUserName;
state.wait.until(ExpectedConditions.visibilityOf(eleUserName));
Assert.assertEquals(userName, eleUserName.getText());
});
}
}
Spring 中的组件是单例。因此,当您创建两个网络驱动程序时,您将它们分配给同一对象的同一字段。这意味着只使用了一个。
据推测,您在升级到 v5 后已经开始遇到这种行为。由于 v5 Cucumber 将在线程之间共享 spring 应用程序上下文(与所有其他 spring 测试一样)。
https://github.com/cucumber/cucumber-jvm/blob/main/CHANGELOG.md#500-rc4-2019-12-21
为确保组件不在场景之间共享,您必须使用 @ScenarioScope
对其进行注释。