目录
[1. TDD 是什么?](#1. TDD 是什么?)
[TDD 示例:计算订单折扣](#TDD 示例:计算订单折扣)
[TDD 关注的是什么?](#TDD 关注的是什么?)
[2. BDD 是什么?](#2. BDD 是什么?)
[BDD 示例:订单折扣](#BDD 示例:订单折扣)
[3. TDD 和 BDD 的核心区别](#3. TDD 和 BDD 的核心区别)
[4. 用一个登录功能对比](#4. 用一个登录功能对比)
[TDD 写法](#TDD 写法)
[BDD 写法](#BDD 写法)
[5. 工程实践中怎么选?](#5. 工程实践中怎么选?)
[推荐方案:TDD 为主,BDD 只覆盖核心业务链路](#推荐方案:TDD 为主,BDD 只覆盖核心业务链路)
[6. 简单总结](#6. 简单总结)
前言:TDD主要是关心函数、类的实现是否符合预期,而BDD则是更多地关注业务逻辑是否正确。具体的简化流程就是TDD:先写一个失败的测试案例,然后编写最小改动的实现让测试通过,后续需要有功能的改进需要在保证测试通过的时候进行代码的重构;BDD:给出业务场景会遇到的情况,在每个情况下分别设计1.Scenario ;2.Given ;3.When ;4.Then
结论
TDD 和 BDD 都是"先定义预期,再写实现"的开发方法。
-
TDD:Test-Driven Development,测试驱动开发
-
关注点:代码逻辑是否正确
-
主要面向:开发者
-
常见形式:单元测试、集成测试
-
核心流程:先写测试 → 测试失败 → 写代码通过测试 → 重构
-
-
BDD:Behavior-Driven Development,行为驱动开发
-
关注点:业务行为是否符合预期
-
主要面向:产品、测试、开发共同理解
-
常见形式:Given / When / Then 场景描述
-
核心流程:先描述业务场景 → 再实现功能 → 验证行为
-
1. TDD 是什么?
TDD 的核心是:
在写业务代码之前,先写测试代码,用测试来反推实现。
典型流程是:
Red :先写一个失败的测试
Green :写最少代码让测试通过
Refactor:重构代码,保持测试通过
TDD 示例:计算订单折扣
需求:
如果订单金额大于等于 100 元,打 9 折;否则不打折。
第一步:先写测试
python
def test_order_discount_when_amount_greater_than_100():
assert calculate_price(100) == 90
assert calculate_price(200) == 180
def test_order_no_discount_when_amount_less_than_100():
assert calculate_price(99) == 99
这时候 calculate_price 还不存在,所以测试一定失败。
这就是 Red 阶段。
第二步:写最少实现代码
python
def calculate_price(amount):
if amount >= 100:
return amount * 0.9
return amount
现在测试通过。
这就是 Green 阶段。
第三步:重构
比如考虑金额精度:
python
from decimal import Decimal
def calculate_price(amount):
amount = Decimal(str(amount))
if amount >= Decimal("100"):
return amount * Decimal("0.9")
return amount
只要测试仍然通过,就说明重构没有破坏原有逻辑。
TDD 关注的是什么?
TDD 主要关注:
这个函数、类、模块的逻辑是否正确?
边界条件是否覆盖?
重构时是否会破坏已有行为?
它更偏向 代码层面的正确性保障。
2. BDD 是什么?
BDD 的核心是:
用接近自然语言的方式描述业务行为,然后用这些行为场景来驱动开发和测试。
BDD 常用格式是:
Given 前置条件
When 发生某个动作
Then 应该得到某个结果
BDD 示例:订单折扣
同样的需求:
如果订单金额大于等于 100 元,打 9 折;否则不打折。
用 BDD 可以这样写:
Feature: 订单折扣
Scenario: 订单金额达到 100 元时享受 9 折优惠
Given 用户有一个金额为 100 元的订单
When 系统计算订单最终价格
Then 最终价格应该是 90 元
Scenario: 订单金额低于 100 元时不享受优惠
Given 用户有一个金额为 99 元的订单
When 系统计算订单最终价格
Then 最终价格应该是 99 元
这段不是普通测试代码,而是业务场景说明。
它的价值在于:
产品能看懂
测试能看懂
开发能实现
业务方也能参与讨论
对应的测试代码可能是这样
以 Python behave 风格举例:
python
@given("用户有一个金额为 {amount:d} 元的订单")
def step_given_order(context, amount):
context.amount = amount
@when("系统计算订单最终价格")
def step_when_calculate_price(context):
context.final_price = calculate_price(context.amount)
@then("最终价格应该是 {expected:d} 元")
def step_then_check_price(context, expected):
assert context.final_price == expected
BDD 的场景描述和测试代码是绑定的。
3. TDD 和 BDD 的核心区别
| 对比项 | TDD | BDD |
|---|---|---|
| 全称 | Test-Driven Development | Behavior-Driven Development |
| 中文 | 测试驱动开发 | 行为驱动开发 |
| 关注点 | 代码逻辑正确性 | 业务行为符合预期 |
| 主要使用者 | 开发者 | 产品、测试、开发 |
| 表达方式 | 测试代码 | Given / When / Then |
| 常见粒度 | 函数、类、模块 | 用户场景、业务流程 |
| 典型工具 | pytest、JUnit、Go test | Cucumber、behave、SpecFlow |
| 更适合 | 算法、服务逻辑、核心模块 | 复杂业务流程、验收测试 |
4. 用一个登录功能对比
TDD 写法
关注的是函数是否返回正确结果。
python
def test_login_success():
user = User(username="alice", password="123456")
result = login("alice", "123456")
assert result.success is True
assert result.user.username == "alice"
def test_login_failed_with_wrong_password():
result = login("alice", "wrong-password")
assert result.success is False
assert result.error == "用户名或密码错误"
这里主要验证的是:
login 函数在不同输入下是否返回正确结果
BDD 写法
关注的是用户行为和系统响应。
Feature: 用户登录
Scenario: 用户使用正确密码登录成功
Given 系统中存在用户名为 "alice" 且密码为 "123456" 的用户
When 用户输入用户名 "alice" 和密码 "123456" 进行登录
Then 系统应该允许用户登录
And 用户应该进入首页
Scenario: 用户使用错误密码登录失败
Given 系统中存在用户名为 "alice" 且密码为 "123456" 的用户
When 用户输入用户名 "alice" 和密码 "wrong-password" 进行登录
Then 系统应该拒绝登录
And 页面应该提示 "用户名或密码错误"
这里更强调:
从用户视角看,系统行为是否符合业务预期
5. 工程实践中怎么选?
推荐方案:TDD 为主,BDD 只覆盖核心业务链路
大多数研发团队更适合这样用:
核心函数、服务逻辑、边界条件:用 TDD
核心业务流程、验收场景:用 BDD
例如:
| 场景 | 推荐方式 |
|---|---|
| 价格计算 | TDD |
| 权限判断 | TDD |
| 数据清洗 | TDD |
| API 参数校验 | TDD |
| 用户下单流程 | BDD |
| 支付成功后的订单状态流转 | BDD |
| 医疗问诊流程 | BDD |
| Agent 工具调用流程验收 | BDD |
不建议的做法
不要为了"流程规范"把所有东西都写成 BDD。
比如一个简单函数:
def add(a, b):
return a + b
写成 BDD 就很重:
Given 用户输入数字 1 和 2
When 系统执行加法
Then 系统应该返回 3
这类场景用普通单元测试就够了。
6. 简单总结
可以这样理解:
TDD:从代码正确性出发
BDD:从业务行为出发
更直观一点:
TDD 问的是:这个函数对不对?
BDD 问的是:这个系统行为是不是用户想要的?
工程上比较成熟的做法是:
多数逻辑用 TDD 保证质量
少数关键业务链路用 BDD 做验收
不要把 BDD 滥用成高成本文档工程