1. 引言

Cucumber 是一个 BDD(行为驱动开发)测试框架。当需要编写大量重复场景(仅输入/输出参数不同)时,传统方式会:

  • 耗时费力
  • 难以维护
  • 让人抓狂 😤

Cucumber 通过场景大纲(Scenario Outline)示例(Examples)的组合完美解决了这个问题。下面我们通过实际案例演示如何高效简化测试用例。

提示:想深入了解 BDD 和 Gherkin 语法?推荐阅读这篇基础教程

2. 添加 Cucumber 依赖

在 Maven 项目中集成 Cucumber 需要以下核心依赖:

<dependency>
    <groupId>info.cukes</groupId>
    <artifactId>cucumber-junit</artifactId>
    <version>1.2.5</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>info.cukes</groupId>
    <artifactId>cucumber-java</artifactId>
    <version>1.2.5</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.hamcrest</groupId>
    <artifactId>hamcrest-library</artifactId>
    <version>1.3</version>
    <scope>test</scope>
</dependency>

⚠️ 所有依赖都设置为 test scope,因为测试库不需要随生产代码部署。

3. 测试对象示例

先定义一个简单的计算器类作为测试目标:

public class Calculator {
    public int add(int a, int b) {
        return a + b;
    }
}

4. 传统 Cucumber 测试定义

4.1. 特性文件(Feature File)

Feature: Calculator
  As a user
  I want to use a calculator to add numbers
  So that I don't need to add myself

  Scenario: Add two numbers -2 & 3
    Given I have a calculator
    When I add -2 and 3
    Then the result should be 1
   
  Scenario: Add two numbers 10 & 15
    Given I have a calculator
    When I add 10 and 15
    Then the result should be 25

❌ 问题:除了数字不同,其他步骤完全重复!新增测试用例需要复制粘贴,维护成本极高。

4.2. 胶水代码(Glue Code)

public class CalculatorRunSteps {

    private int total;
    private Calculator calculator;

    @Before
    private void init() {
        total = -999;
    }

    @Given("^I have a calculator$")
    public void initializeCalculator() throws Throwable {
        calculator = new Calculator();
    }

    @When("^I add (-?\\d+) and (-?\\d+)$")
    public void testAdd(int num1, int num2) throws Throwable {
        total = calculator.add(num1, num2);
    }

    @Then("^the result should be (-?\\d+)$")
    public void validateResult(int result) throws Throwable {
        Assert.assertThat(total, Matchers.equalTo(result));
    }
}

4.3. 测试运行器

@RunWith(Cucumber.class)
@CucumberOptions(
  features = { "classpath:features/calculator.feature" },
  glue = {"com.baeldung.cucumber.calculator" })
public class CalculatorTest {}

5. 使用场景大纲重构

现在用场景大纲彻底改造特性文件:

Feature: Calculator
  As a user
  I want to use a calculator to add numbers
  So that I don't need to add myself

  Scenario Outline: Add two numbers <num1> & <num2>
    Given I have a calculator
    When I add <num1> and <num2>
    Then the result should be <total>

  Examples: 
    | num1 | num2 | total |
    | -2   | 3    | 1     |
    | 10   | 15   | 25    |
    | 99   | -99  | 0     |
    | -1   | -10  | -11   |

✅ 核心优势:

  • 步骤定义用 <参数名> 占位
  • 测试数据通过 Examples 表格集中管理
  • 新增用例只需添加一行数据

Examples 表格语法规范

Examples:
  | 参数名1 | 参数名2 |
  | 值-1    | 值-2    |
  | 值-X    | 值-Y    |

6. 总结

通过场景大纲,我们实现了:

  • ✅ 测试场景参数化
  • ✅ 减少重复代码
  • ✅ 简化用例维护
  • ✅ 提升可读性

完整示例代码可在 GitHub 获取

踩坑提醒:确保参数名(如 <num1>)与 Examples 表头完全匹配,否则会报 cucumber.runtime.CucumberException: Parameter not found 错误!


原始标题:Cucumber and Scenario Outline