1. 引言
Cucumber 是支持行为驱动开发(BDD)的测试工具。BDD 的核心优势在于让非技术人员能用自然语言描述业务功能。
定义 Cucumber 测试的基石是特性(Features)、场景(Scenarios)和步骤(Steps),这些必须用 Gherkin 语言编写。本文将介绍如何在 Cucumber 的步骤间共享数据。
2. 环境准备
我们用一个处理事件的 Spring Boot 应用演示数据共享。测试将验证事件的生命周期:从进入系统的初始状态到处理后的最终状态。
先定义 Event
类:
public class Event {
private String uuid;
private EventStatus status;
// 标准 getter/setter
}
public enum EventStatus {
PROCESSING, ERROR, COMPLETE
}
事件处理时,状态会从初始的 PROCESSING
转为最终状态(COMPLETE
或 ERROR
)。
现在编写初始场景和步骤定义:
Scenario: 新事件正确初始化
When 新事件进入系统
Then 事件正确初始化
下节将展示两个步骤如何共享事件数据。
3. 使用 Spring 共享步骤数据
@ScenarioScope
注解允许在场景的步骤间共享状态。它指示 Spring 为每个场景创建新实例,既保证步骤间数据共享,又防止场景间状态泄露。
实现步骤定义前,先创建 SharedEvent
测试类存储共享数据:
@Component
@ScenarioScope
public class SharedEvent {
private Event event;
private Instant createdAt;
private Instant processedAt;
// 标准 getter/setter
}
SharedEvent
在 Event
基础上增加了 createdAt
和 processedAt
字段,便于编写更复杂的场景。
最后定义场景步骤:
public class EventSteps {
static final String UUID = "1ed80153-666c-4904-8e03-08c4a41e716a";
static final String CREATED_AT = "2024-12-03T09:00:00Z";
@Autowired
private SharedEvent sharedEvent;
@When("新事件进入系统")
public void createNewEvent() {
Event event = new Event();
event.setStatus(EventStatus.PROCESSING);
event.setUuid(UUID);
sharedEvent.setEvent(event);
sharedEvent.setCreatedAt(Instant.parse(CREATED_AT));
}
@Then("事件正确初始化")
public void verifyEventIsInitialized() {
Event event = sharedEvent.getEvent();
assertThat(event.getStatus()).isEqualTo(EventStatus.PROCESSING);
assertThat(event.getUuid()).isEqualTo(UUID);
assertThat(sharedEvent.getCreatedAt().toString()).isEqualTo(CREATED_AT);
assertThat(sharedEvent.getProcessedAt()).isNull();
}
}
运行特性文件后,createNewEvent()
和 verifyEventIsInitialized()
通过 SharedEvent
成功共享数据。
3.1. 扩展场景
再编写两个多步骤场景:
Scenario: 事件处理成功
Given 新事件进入系统
When 事件处理成功
Then 事件状态为 COMPLETE
And 事件包含 processedAt
Scenario: 系统错误导致事件处理失败
Given 新事件进入系统
When 事件处理失败
Then 事件状态为 ERROR
And 事件包含 processedAt
在 EventSteps
类中添加新步骤定义,展示 Gherkin 的可读性和复用性特性:
实现 When 步骤:
static final String PROCESSED_AT = "2024-12-03T10:00:00Z";
@When("事件处理 (succeeds|fails)$")
public void processEvent(String processingStatus) {
// 处理事件逻辑...
EventStatus eventStatus = "succeeds".equalsIgnoreCase(processingStatus) ?
EventStatus.COMPLETE : EventStatus.ERROR;
sharedEvent.getEvent().setStatus(eventStatus);
sharedEvent.setProcessedAt(Instant.parse(PROCESSED_AT));
}
"事件处理 (succeeds|fails)$"
是正则表达式,可复用匹配"事件处理成功/失败"。结尾 $
确保精确匹配,避免误识别多余字符。
实现 Then 步骤(验证 processedAt):
@Then("事件包含 processedAt")
public void verifyProcessedAt() {
assertThat(sharedEvent.getProcessedAt().toString()).isEqualTo(PROCESSED_AT);
}
实现 Then 步骤(验证状态):
@Then("事件状态为 {status}")
public void verifyEventStatus(EventStatus status) {
assertThat(sharedEvent.getEvent().getStatus()).isEqualTo(status);
}
@ParameterType("PROCESSING|ERROR|COMPLETE")
public EventStatus status(String statusName) {
return EventStatus.valueOf(statusName);
}
Cucumber 的参数类型支持将表达式转换为对象。**@ParameterType
注解的 status()
方法将字符串转为 EventStatus
枚举**。通过 {status}
占位符调用,可匹配三个步骤:
- 事件状态为 PROCESSING
- 事件状态为 COMPLETE
- 事件状态为 ERROR
运行新场景时,多个步骤成功共享数据。
4. 总结
本文介绍了在 Cucumber 中共享步骤数据的方法。这种机制既支持场景内数据共享,又能隔离不同场景的数据。⚠️ 需注意:步骤间数据共享会强耦合代码,降低复用性。
完整代码见 GitHub 仓库。