大多数开发者都听说过测试驱动开发。大多数人没有认真尝试过。尝试过的人要么喜欢它,要么错误地尝试过然后放弃了。TDD 不是关于写测试。它是关于更快地写出更好的代码。关键是要去做。
每个人都搞错了什么
TDD 不是"写测试,然后写代码"。它是"写一个失败的测试,写最少的代码使其通过,然后重构"。重构步骤很重要。大多数人跳过它。这就是为什么他们认为 TDD 很慢。
红-绿-重构是循环。写一个失败的测试(红色)。只写足够通过的代码(绿色)。清理你制造的混乱(重构)。重复直到功能完成。测试给你重构而不破坏东西的许可。
第一次尝试 TDD 的人通常会写一个测试,然后写整个功能,然后想知道为什么测试立即通过了。你应该先看着它失败。失败的测试证明你的测试测试了某些东西。
为什么它有效
TDD 迫使你在写代码之前思考代码将如何被使用。如果你的测试很难写,你的 API 可能很糟糕。修复 API。这是设计压力。这是 TDD 的主要好处,大多数人完全错过了它。
# 没有 TDD,你可能会写这个
def process_user_data(user_id):
db = Database()
conn = db.connect()
user = conn.query("SELECT * FROM users WHERE id = ?", user_id)
# 另外 50 行数据库逻辑与业务逻辑混合
return result
# 有了 TDD,测试迫使你分离关注点
def test_process_user_data():
user = User(id=1, name="Test")
result = process_user_data(user)
assert result.status == "processed"第二个版本是可测试的,因为测试迫使你将数据访问与业务逻辑分离。你无法轻松测试第一个版本而不连接真实数据库。TDD 通过使糟糕的设计难以测试来推动你走向更好的设计。
时间问题
"我没有时间写测试"是倒过来的。TDD 节省时间。这是数学。没有测试,你写代码,手动测试它,发布它,在生产中发现 bug,上下文切换回来修复它们,并希望你没有破坏其他东西。
有了 TDD,你写测试,写代码,然后你完成了。测试在你仍在代码中时立即捕获 bug。没有上下文切换。没有生产火灾。没有"我以后会测试它"但永远不会发生。
TDD 的第一周是慢的。你在学习。之后,你比以前更快。一个月后,你想知道你怎么可能在没有测试的情况下发布代码。投资回报是以天为单位衡量的,不是月。
测试什么
测试行为,不是实现。不要测试一个函数调用另一个函数。测试当你调用函数时,你得到正确的结果。实现细节可以改变。行为应该保持一致。
// 糟糕的测试 - 测试实现
test('user registration calls database.insert', () => {
const db = mock(Database)
registerUser(db, 'test@example.com')
expect(db.insert).toHaveBeenCalled()
})
// 好的测试 - 测试行为
test('user registration creates an account', () => {
registerUser('test@example.com', 'password')
const user = findUserByEmail('test@example.com')
expect(user).toBeDefined()
expect(user.email).toBe('test@example.com')
})第一个测试在你每次重构用户存储方式时都会中断。第二个测试只在注册停止工作时才会中断。测试行为。
当 TDD 很难时
TDD 在探索性代码上有困难。如果你还不确定你在构建什么,先写一次性代码。一旦你搞清楚了,删除所有内容并用 TDD 重新做一遍。第二次总是更快更干净。
UI 代码很棘手。你可以 TDD UI 背后的逻辑,但测试"按钮是蓝色的"通常不值得。测试点击按钮做正确的事情,而不是按钮看起来正确。
没有测试的遗留代码是噩梦。你不能轻松地 TDD 对未测试代码的更改。解决方案是添加特征测试来记录代码当前做什么,然后 TDD 新功能。随着时间的推移,代码库变得更好。
工具不太重要
每种语言都有测试框架。JavaScript 的 Jest。Python 的 pytest。Java 的 JUnit。PHP 的 PHPUnit。它们都工作得很好。选择你的语言中最流行的然后继续前进。工具不会使 TDD 工作。纪律会。
快速测试比框架更重要。如果你的测试需要 10 秒才能运行,你不会经常运行它们。如果可能的话,保持测试在一秒以内。对像数据库和 HTTP 调用这样慢的东西使用模拟。快速反馈使 TDD 愉快。慢速反馈使它痛苦。
明天开始是错误的
开始 TDD 的最佳时间是你的第一个项目。第二好的时间是现在。选择你需要写的下一个函数。先写测试。看着它失败。让它通过。重构。再做一次。
不要试图立即 TDD 一切。不要回去为旧代码添加测试,除非你正在更改它。从新代码开始。一次一个函数。逐渐养成习惯。几周后,它变得自动。
从不开始 TDD 的开发者一直在犯同样的错误。开始 TDD 然后一天后放弃的开发者从未给它真正的机会。坚持两周的开发者通常会永远坚持下去。
TDD 不是银弹。它本身不会修复糟糕的代码或糟糕的架构。但它会使你的代码更好,你的 bug 更少,你的信心更高。今天开始。
相关阅读
想要提升你的开发职业?查看:
- 2025 年 Web 开发职业现实检查 - 关于 2025 年作为 Web 开发者成功需要什么的诚实建议
Fred
AUTHORFull-stack developer with 10+ years building production applications. I write about cloud deployment, DevOps, and modern web development from real-world experience.
Need a developer who gets it?
POC builds, vibe-coded fixes, and real engineering. Let's talk.
Hire Me →
