Cucumber Scenario Outline示例表仅执行一次问题求助
Cucumber Scenario Outline仅执行第一组数据问题排查
我是Cucumber新手,正在学习自动化测试。编写了包含Scenario Outline和Examples表的Demo.feature文件,表内有3组登录测试凭证,但运行后仅执行第一组数据,控制台显示仅1个Scenario执行成功,其余两组未运行,请求协助排查解决该问题。
相关代码文件
Demo.feature
Feature: Test login functionality Scenario Outline: Check login is successful with valid credentials Given browser is open And user is on login page When user enters <username> and <password> And user clicks on login Then user is navigated to the home page Examples: | username | password | | student | Password123 | | Raghav | pass123 | | dil | dill2 |
该表仅运行第一组用户名和密码,未执行全部3组数据。
StepDefinition: DemoSteps.java
import java.util.concurrent.TimeUnit; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import io.cucumber.java.en.*; public class LoginDemoSteps { WebDriver driver = null; @Given("browser is open") public void browser_is_open() { System.out.println("inside step - browser open"); String projectPath = System.getProperty("user.dir");//获取当前项目文件夹路径 System.out.println(projectPath); System.setProperty("webdriver.chrome.driver",projectPath+"/src/test/resources/drivers/chromedriver.exe"); driver = new ChromeDriver(); driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);//等待元素加载的全局超时 driver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS);//等待页面加载超时 //页面加载完成后会跳过这两个等待 } @And("user is on login page") public void user_is_on_login_page() { driver.navigate().to("https://practicetestautomation.com/practice-test-login/"); } @When("^user enters (.*) and (.*)$") public void user_enters_username_and_password(String username, String password) throws InterruptedException { driver.findElement(By.id("username")).sendKeys(username); driver.findElement(By.id("password")).sendKeys(password); Thread.sleep(2000); } @And("user clicks on login") public void user_clicks_on_login() { //id=submit driver.findElement(By.id("submit")).click(); } @Then("user is navigated to the home page") public void user_is_navigated_to_the_home_page() throws InterruptedException { driver.getPageSource().contains("Logged In Successfully");//检查页面是否包含指定文本 System.out.println("Test Successful"); Thread.sleep(2000); driver.close(); driver.quit(); } }
RunnerClass : TestRunner.java
package StepDefinitions; import org.junit.runner.RunWith; import io.cucumber.junit.CucumberOptions; import io.cucumber.junit.Cucumber; //用于运行所有自动化步骤的类 @RunWith(Cucumber.class) @CucumberOptions(features = "src/test/resources/Features", glue = { "StepDefinitions" }, //关联步骤定义代码 monochrome = true, plugin = { "pretty", "html:target/HTMLReports/report.html", "json:target/JSONReports/report.json", "junit:target/JUNITReports/report.xml" } //报告输出配置 ) public class TestRunner { }
控制台输出结果
Feb 28, 2024 1:59:26 PM cucumber.api.cli.Main run WARNING: You are using deprecated Main class. Please use io.cucumber.core.cli.Main Scenario: Check login is successful with valid credentials # src/test/resources/Features/LoginDemo.feature:3 inside step - browser open C:\Users\..\CucumberJava2 Given browser is open # StepDefinitions.LoginDemoSteps.browser_is_open() And user is on login page # StepDefinitions.LoginDemoSteps.user_is_on_login_page() When user enters username and password # StepDefinitions.LoginDemoSteps.user_enters_username_and_password() And user clicks on login # StepDefinitions.LoginDemoSteps.user_clicks_on_login() Test Successful Feb 28, 2024 1:59:33 PM org.openqa.selenium.remote.http.WebSocket$Listener onError WARNING: Connection reset java.net.SocketException: Connection reset at java.base/sun.nio.ch.SocketChannelImpl.throwConnectionReset(SocketChannelImpl.java:394) at java.base/sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:426) at java.net.http/jdk.internal.net.http.SocketTube.readAvailable(SocketTube.java:1170) at java.net.http/jdk.internal.net.http.SocketTube$InternalReadPublisher$InternalReadSubscription.read(SocketTube.java:833) at java.net.http/jdk.internal.net.http.SocketTube$SocketFlowTask.run(SocketTube.java:181) at java.net.http/jdk.internal.net.http.common.SequentialScheduler$SchedulableTask.run(SequentialScheduler.java:230) at java.net.http/jdk.internal.net.http.common.SequentialScheduler.runOrSchedule(SequentialScheduler.java:303) at java.net.http/jdk.internal.net.http.common.SequentialScheduler.runOrSchedule(SequentialScheduler.java:256) at java.net.http/jdk.internal.net.http.SocketTube$InternalReadPublisher$InternalReadSubscription.signalReadable(SocketTube.java:774) at java.net.http/jdk.internal.net.http.SocketTube$InternalReadPublisher$ReadEvent.signalEvent(SocketTube.java:957) at java.net.http/jdk.internal.net.http.SocketTube$SocketFlowEvent.handle(SocketTube.java:253) at java.net.http/jdk.internal.net.http.HttpClientImpl$SelectorManager.handleEvent(HttpClientImpl.java:979) at java.net.http/jdk.internal.net.http.HttpClientImpl$SelectorManager.lambda$run$3(HttpClientImpl.java:934) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at java.net.http/jdk.internal.net.http.HttpClientImpl$SelectorManager.run(HttpClientImpl.java:934) Then user is navigated to the home page # StepDefinitions.LoginDemoSteps.user_is_navigated_to_the_home_page() 1 Scenarios (1 passed) 5 Steps (5 passed) 0m6.839s
注:Deprecated Main Class并非问题所在。
问题原因及解决方案
问题根源
在LoginDemoSteps类的@Then步骤方法中,执行了driver.quit()——该方法会彻底终止整个WebDriver会话。第一组数据执行完成后,WebDriver已被完全关闭,后续的Scenario迭代无法再初始化新的浏览器实例,导致其余两组数据根本没有运行机会。此外,driver.close()关闭当前窗口后再调用driver.quit()属于重复操作,quit()本身就会关闭所有关联窗口并终止会话。
修复方案
使用Cucumber的@After钩子统一管理浏览器生命周期,确保每个Scenario(即每组测试数据)执行完成后再关闭浏览器,而不是在步骤方法中直接终止会话:
修改后的LoginDemoSteps.java:
import java.util.concurrent.TimeUnit; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import io.cucumber.java.After; import io.cucumber.java.en.*; import static org.junit.Assert.assertTrue; public class LoginDemoSteps { WebDriver driver = null; @Given("browser is open") public void browser_is_open() { System.out.println("inside step - browser open"); String projectPath = System.getProperty("user.dir"); System.out.println(projectPath); System.setProperty("webdriver.chrome.driver",projectPath+"/src/test/resources/drivers/chromedriver.exe"); driver = new ChromeDriver(); driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS); driver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS); } @And("user is on login page") public void user_is_on_login_page() { driver.navigate().to("https://practicetestautomation.com/practice-test-login/"); } @When("^user enters (.*) and (.*)$") public void user_enters_username_and_password(String username, String password) throws InterruptedException { driver.findElement(By.id("username")).sendKeys(username); driver.findElement(By.id("password")).sendKeys(password); Thread.sleep(2000); } @And("user clicks on login") public void user_clicks_on_login() { driver.findElement(By.id("submit")).click(); } @Then("user is navigated to the home page") public void user_is_navigated_to_the_home_page() throws InterruptedException { // 使用断言明确验证结果,失败时会抛出错误 assertTrue("登录失败,未跳转到成功页面", driver.getPageSource().contains("Logged In Successfully")); System.out.println("Test Successful"); Thread.sleep(2000); } // 添加After钩子,每个Scenario执行完成后关闭浏览器会话 @After public void tearDown() { if (driver != null) { driver.quit(); } } }
额外优化建议
- 替换
Thread.sleep()为Selenium的显式等待(WebDriverWait),避免固定等待时间导致的测试不稳定和效率低下。 - 始终使用断言验证测试结果,而非仅打印信息,这样测试失败时能直接定位问题。
内容的提问来源于stack exchange,提问作者Tharun S M
相关产品推荐
相关产品推荐

