本文目录导读:

- 核心概念:用户故事 vs BDD场景
- 将用户故事与BDD结合的标准结构
- 核心要素:Given-When-Then 语法
- 实战案例:电商网站的“退货”功能
- BDD的核心优势(为什么这么做)
- 最佳实践Tips
- 总结一句话
这是一个关于 BDD(行为驱动开发) 与 用户故事 结合的完整指南,我们将从核心理念、如何编写、到具体例子进行详细说明。
核心概念:用户故事 vs BDD场景
首先需要理清它们的关系:
- 用户故事: 关注的是 “什么” (What),它描述了一个功能从用户角度出发的价值,通常格式是:As a... I want... So that...
- BDD场景: 关注的是 “如何” (How),它描述了用户故事中具体的、可测试的行为,通常格式是:Given... When... Then...
关键点: BDD是用具体的、可执行的例子来补充和细化用户故事,从而确保团队(业务、开发、测试)对需求有一致的理解。
将用户故事与BDD结合的标准结构
一个完整的使用BDD的用户故事应该包含两部分:
- 用户故事标题与主体: 描述用户角色、功能、目标。
- 验收标准(BDD场景): 使用 Given-When-Then 格式编写的、可自动化的测试用例集合。
核心要素:Given-When-Then 语法
这是BDD的基石,请务必深入理解:
- Given(给定): 上下文,系统处于什么样的初始状态?(用户已登录,账户余额为100元)
- When(当): 事件,用户执行了什么操作?(用户点击“提现”按钮,输入50元并提交)
- Then(: 结果,系统应该产生什么样的可观察行为?(用户收到“提现成功”提示,账户余额变为50元)
进阶语法(企业级):
- And(: 连接多个Given、When或Then。
- But(: 用于描述例外、约束或否定情况。
实战案例:电商网站的“退货”功能
让我们通过一个具体案例来看BDD如何驱动测试。
用户故事
用户故事标题: 顾客申请退货refund
- As a 已购物的顾客
- I want to 在订单送达后30天内申请退货
- So that 我可以拿到退款或进行换货
初步的讨论(背景): 团队需要明确细节,运费谁出?商品状态要求?退货运费规则?
转化为BDD场景(验收标准)
我们将上述用户故事分解为多个BDD场景,每个场景都是一个独立的可测试行为。
场景1:成功退货(正常流程)
Scenario: 顾客在允许时间内成功申请退货退款
Given 顾客“张三”已登录
And “张三”有一个已送达的订单“ORDER-001”
And 该订单的商品“蓝牙耳机”状态为“未拆封”
And 当前日期距离送达日期为7天(小于30天)
When 顾客“张三”在订单详情页点击“申请退货”按钮
And 选择退货原因为“商品尺寸不符”
And 提交退货申请
Then 系统显示“退货申请已提交”
And 系统生成一笔退货记录,状态为“待审核”
And 系统发送退货通知给客服团队
场景2:退货失败——超过退货期限
Scenario: 顾客申请退货时,已超过退货期限
Given 顾客“张三”已登录
And “张三”有一个已送达的订单“ORDER-002”
And 当前日期距离送达日期为35天(超过30天)
When 顾客“张三”在订单详情页点击“申请退货”按钮
Then 系统显示错误提示:“很抱歉,该订单已超过退货期限(30天)”
And 系统中该订单的“退货”按钮处于禁用状态
场景3:退货失败——商品已使用
Scenario: 顾客申请退货时,商品已拆封且使用
Given 顾客“张三”已登录
And “张三”有一个已送达的订单“ORDER-003”
And 该订单的商品“蓝牙耳机”状态为“已使用”(不符合退货政策)
When 顾客“张三”在订单详情页点击“申请退货”按钮
Then 系统显示错误提示:“该商品已使用,不符合退货条件”
场景4:退货有运费抵扣
Scenario: 顾客提交非质量问题退货,退款扣除运费
Given 顾客“张三”已登录
And 订单“ORDER-001”配送地址为“北京市”且使用了免运费优惠
And 退货原因为“个人原因”(非质量问题)
When 顾客成功提交退货申请
Then 系统计算的退款金额为:商品价格 - 原订单的运费金额(假设为10元)
BDD的核心优势(为什么这么做)
- 单一真相来源: 这份 Gherkin 文件是业务、开发、测试三方共同维护的“活文档”。
- 可执行需求: 这些场景可以直接使用 Cucumber、SpecFlow 等框架自动化为测试脚本。
- 减少返工: 在编码前就澄清了歧义(不同退货原因的运费规则是什么?)。
- 驱动设计: 开发者会根据 Given-When-Then 来设计代码结构(如状态模式、策略模式处理不同退货条件)。
最佳实践Tips
- 用业务语言,不要使用技术术语。 写“顾客点击‘提交’按钮”,而不是“触发POST /api/return请求”。
- 每个场景只测试一个独立的行为。 不要在一个长长的场景里测试所有情况,分场景3、场景4。
- Given 是“上下文”,不是“操作”。 Given 部分应设置好前置状态,而不是描述用户操作。
- ❌
Given 顾客输入了用户名和密码 - ✅
Given 顾客已登录
- ❌
- 场景数量控制在5-15个以内 针对一个用户故事,太多可能表示故事太大了(需要拆分)。
- 使用
Examples表格(数据驱动): 当场景逻辑相同但输入数据不同时,使用表格减少重复。
Scenario Outline: 计算不同订单金额的运费
Given 顾客的订单总额为 <订单金额>
When 顾客满足包邮条件
Then 应免运费
Examples:
| 订单金额 |
| 200 |
| 0 | # 特殊情况
| 99.9 | # 边界值
总结一句话
一个好的BDD测试用户故事 = 清晰描述价值的用户故事 + 一组用 Given-When-Then 写成的、可直接自动化的验收场景。