You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 21:27:10