一、TDD三大步骤图解(Python版)
# TDD循环伪代码
while 有未实现需求:1. 写新测试 -> 运行测试 -> 看到失败(红)❌2. 写最少代码 -> 运行测试 -> 看到通过(绿)✅3. 优化代码结构 -> 运行测试 -> 确保仍通过(重构)🔧
二、环境准备
确保安装Python和pytest:
pip install pytest
创建文件:
touch calculator.py # 实现代码
touch test_calculator.py # 测试代码
三、实战案例:开发「字符串计算器」
需求:实现一个add
函数,计算字符串数字之和
例如:add("1,2")
返回 3
第1轮:空字符串返回0
步骤1️⃣ 写失败测试(红)
# test_calculator.py
import pytest
from calculator import adddef test_empty_string_should_return_zero():assert add("") == 0 # ❌ 测试失败(红)
运行测试(会失败):
pytest test_calculator.py
步骤2️⃣ 写最少代码通过测试(绿)
# calculator.py
def add(numbers):return 0 # ✅ 最简单实现让测试通过
再次运行测试 → 通过(绿)✅
第2轮:单个数字返回自身
步骤1️⃣ 写失败测试(红)
# test_calculator.py
def test_single_number_should_return_itself():assert add("5") == 5 # ❌ 当前返回0,测试失败
步骤2️⃣ 写最少代码通过测试(绿)
# calculator.py
def add(numbers):if numbers == "": return 0return int(numbers) # ✅ 处理单个数字
第3轮:两个数字求和
步骤1️⃣ 写失败测试(红)
def test_two_numbers_should_return_sum():assert add("3,5") == 8 # ❌ 当前只能处理单个数字
步骤2️⃣ 写最少代码通过测试(绿)
def add(numbers):if numbers == "":return 0if "," in numbers:num_list = numbers.split(",")return int(num_list[0]) + int(num_list[1])return int(numbers)
第4轮:重构优化代码
def add(numbers):if not numbers: # 更简洁的空值判断return 0num_list = numbers.split(",")total = 0for num in num_list:total += int(num)return total # ✅ 支持任意数量数字
重构后验证:所有测试仍然通过 ✅
第5轮:处理新需求(支持换行符)
步骤1️⃣ 写失败测试(红)
def test_newline_delimiter():assert add("1\n2,3") == 6 # ❌ 当前无法识别\n
步骤2️⃣ 写实现代码(绿)
def add(numbers):if not numbers:return 0# 替换换行符为逗号numbers = numbers.replace("\n", ",")num_list = numbers.split(",")total = 0for num in num_list:total += int(num)return total
第6轮:边界情况处理(负数检测)
步骤1️⃣ 写失败测试(红)
def test_negative_number_raises_exception():with pytest.raises(ValueError): # 期望抛出异常add("-1,2") # ❌ 当前未处理负数
步骤2️⃣ 写实现代码(绿)
def add(numbers):if not numbers:return 0numbers = numbers.replace("\n", ",")num_list = numbers.split(",")negatives = []total = 0for num in num_list:n = int(num)if n < 0:negatives.append(str(n))total += nif negatives:raise ValueError(f"负数不允许: {', '.join(negatives)}")return total
四、TDD完整测试套件示例
# test_calculator.py
import pytest
from calculator import adddef test_empty_string():assert add("") == 0def test_single_number():assert add("5") == 5assert add("10") == 10def test_two_numbers():assert add("3,5") == 8assert add("10,20") == 30def test_multiple_numbers():assert add("1,2,3,4") == 10def test_newline_delimiter():assert add("1\n2,3") == 6def test_negative_number():with pytest.raises(ValueError) as e:add("-1,2,-3")assert "负数不允许: -1, -3" in str(e.value)def test_large_numbers():assert add("1000,2") == 1002
五、TDD核心优势图解
六、给Python初学者的TDD黄金法则
- 测试文件命名:
test_*.py
或*_test.py
- 测试函数命名:
test_功能描述
(如test_add_negative_numbers
) - 使用pytest快捷命令:
pytest -v # 详细模式 pytest -x # 遇到第一个失败就停止 pytest --lf # 只运行上次失败的测试
- 测试隔离原则:每个测试独立运行,不依赖其他测试状态
- 3A模式写测试:
def test_example():# Arrange - 准备测试数据data = "1,2,3"# Act - 执行操作result = add(data)# Assert - 验证结果assert result == 6
七、常见问题解答
Q:TDD会不会增加工作量?
A:短期多花30%时间写测试,但长期节省50%调试时间
Q:什么情况不用TDD?
Q:测试应该覆盖哪些情况?
- 正常用例 2. 边界值 3. 错误输入 4. 极端情况
Q:如何开始实践?
# 新手练习路线
exercises = ["字符串反转函数","计算器(加减乘除)","用户密码验证器","文件格式转换器"
]
今日行动:选择一个小功能(如:判断回文字符串),尝试TDD三步循环!
记住:红→绿→重构 是TDD的心跳节奏,坚持21天将成为你的本能反应。