本文目录导读:

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文档,减少沟通误解,当代码逻辑改变时,自动化测试会失败,从而提醒团队“业务规则被破坏了”。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播