本文目录导读:

BDD(行为驱动开发)案例通常围绕一个具体的用户故事展开,通过“Given-When-Then”结构描述预期行为。
这里提供3个不同风格的案例,从业务需求到代码实现的完整闭环,供你参考。
电商系统 - 优惠券叠加规则
【背景】
产品经理新出一个规则:“满减券”和“折扣券”不能叠加使用,系统自动选择优惠力度最大的方案。
用户故事 (User Story)
作为 一位网购用户 我希望 在结算时系统能自动选择最优优惠 以便于 我用最少的钱买到心仪的商品
验收标准 (BDD Scenario - Gherkin 语言)
这是BDD最核心的部分,通常写在 .feature 文件中:
# file: checkout_discount.feature
Feature: 结算页优惠计算
作为购物者
我希望系统自动计算最优优惠
以便于支付最少的金额
Scenario: 满减券优于折扣券时,自动使用满减券
Given 我的购物车中有价值 "500" 元的商品
And 我有一张 "满400减50" 的满减券
And 我有一张 "9折" 的折扣券
When 我点击结算按钮
Then 系统应该展示应付金额为 "450" 元
And 系统应展示优惠说明为 "已使用满减券"
Scenario: 折扣券优于满减券时,自动使用折扣券
Given 我的购物车中有价值 "200" 元的商品
And 我有一张 "满199减20" 的满减券
And 我有一张 "8折" 且最高抵扣50元的折扣券
When 我点击结算按钮
Then 系统应该展示应付金额为 "160" 元
And 系统应展示优惠说明为 "已使用折扣券"
Scenario: 优惠券均不满足条件时,原价支付
Given 我的购物车中有价值 "100" 元的商品
And 我有一张 "满200减10" 的满减券
And 我有一张 "9.5折" 的折扣券
When 我点击结算按钮
Then 系统应该展示应付金额为 "100" 元
And 系统应提示 "暂无可用的优惠券"
自动化测试实现 (以 Python Behave 为例)
BDD的关键在于“活文档”——上面的Gherkin文本直接驱动代码运行。
# file: steps/test_checkout_steps.py
from behave import given, when, then
# 上下文存储数据
@given('我的购物车中有价值 "{price}" 元的商品')
def step_cart_price(context, price):
context.cart_price = float(price)
@given('我有一张 "{rule}" 的满减券')
def step_full_reduction(context, rule):
# 解析规则 "满400减50"
parts = rule.split('减')
threshold = float(parts[0].replace('满', ''))
discount = float(parts[1])
context.full_reduction = {'threshold': threshold, 'discount': discount}
@given('我有一张 "{discount}" 的折扣券')
def step_discount_coupon(context, discount):
# 只做简单存储,实际会解析折扣率
context.discount_coupon = float(discount.replace('折', '')) / 10
@when('我点击结算按钮')
def step_click_checkout(context):
# 核心业务算法:模拟真实逻辑
best_price = context.cart_price
best_message = "暂无可用的优惠券"
# 方案1:满减计算
if hasattr(context, 'full_reduction'):
fr = context.full_reduction
if context.cart_price >= fr['threshold']:
candidate = context.cart_price - fr['discount']
if candidate < best_price:
best_price = candidate
best_message = "已使用满减券"
# 方案2:折扣计算(注意该案例中折扣没有封顶,为了简化)
if hasattr(context, 'discount_coupon'):
candidate = context.cart_price * context.discount_coupon
if candidate < best_price:
best_price = candidate
best_message = "已使用折扣券"
context.final_price = best_price
context.final_message = best_message
@then('系统应该展示应付金额为 "{expected}" 元')
def step_check_price(context, expected):
assert context.final_price == float(expected), f"预期{expected},实际{context.final_price}"
@then('系统应展示优惠说明为 "{expected_msg}"')
def step_check_msg(context, expected_msg):
assert context.final_message == expected_msg, f"预期{expected_msg},实际{context.final_message}"
@then('系统应提示 "{expected_msg}"')
def step_check_prompt(context, expected_msg):
assert context.final_message == expected_msg, f"预期提示{expected_msg},实际{context.final_message}"
银行系统 - ATM取款
【业务规则】 用户余额不足时,ATM机拒绝出钞,并先退卡。
BDD 场景描述:
Feature: ATM取款
Scenario: 账户余额不足,取款失败
Given 我的储蓄卡余额为 100 元
And 我的银行卡密码是正确的
When 我在ATM机上取款 200 元
Then ATM机应该提示 "余额不足"
And 系统应该发出退卡指令
技术实现 - 登录功能(含Mock)
【业务规则】 用户输入验证码错误超过5次,账号锁定30分钟。
Feature: 用户登录安全策略
Scenario Outline: 连续输错验证码导致账号锁定
Given 用户 "<username>" 存在且状态为启用
When 用户连续输入错误验证码 "<times>" 次
Then 该账号状态应变为 "锁定"
And 系统应记录锁定时间为 "30" 分钟
Examples:
| username | times |
| test01 | 5 |
| test02 | 6 |
如何撰写有效的BDD案例?(核心要点总结)
-
使用业务语言,而非技术语言
- ✅ 错误写法:
Given 用户点击了名称为"Submit"的按钮 (Button ID=101) - ❌ 正确写法:
Given 用户提交了有效的登录表单
- ✅ 错误写法:
-
关注行为,而非实现细节
BDD不关心数据库怎么存的,只关心界面上显示什么、接口返回什么结果。
-
“Given-When-Then”是铁三角
- Given (上下文):描述初始状态,如“用户已登录”、“卡内余额有100元”。
- When (触发动作):用户做了什么操作,如“点击结算”、“取款200元”。
- Then (预期结果):系统如何响应,如“页面显示成功”、“数据库写入记录”。
-
避免“And”使用过度
- 如果一个场景里有超过5个
And,说明场景可能过于复杂,建议拆分成多个小场景。
- 如果一个场景里有超过5个
BDD工具链推荐
- Cucumber (Ruby/Java/Javascript)
- Behave (Python)
- SpecFlow (.NET)
- JBehave (Java)
BDD的价值在于: 它是一份可执行的规格说明书,产品经理、开发、测试、业务人员都看同一份Gherkin文档,减少沟通误解,当代码逻辑改变时,自动化测试会失败,从而提醒团队“业务规则被破坏了”。