写代码前先写测试?听起来反直觉
刚接触测试驱动开发(TDD)的人,第一反应往往是:还没开始写功能,怎么就要写测试?这就像做饭前先尝味道,逻辑上说不通。但当你真正用它写出几段稳定、可维护的代码后,就会发现这种“反着来”的方式,反而让编程更踏实。
我第一次在项目中实践 TDD,是写一个用户注册接口。按老习惯,我会直接写逻辑,再手动点前端表单测试。但那次我忍住没写实现,而是先写了几个测试用例:邮箱格式不对应该失败,密码太短也应该失败,重复注册要提示错误。这些场景平时都是“测的时候才发现”,但现在,它们成了代码的起点。
describe('User Registration', () => {
it('should reject invalid email', () => {
const user = { email: 'not-an-email', password: '123456' }
expect(register(user)).toBe(false)
})
it('should reject short password', () => {
const user = { email: 'test@example.com', password: '123' }
expect(register(user)).toBe(false)
})
})测试不是负担,是设计说明书
很多人觉得写测试是额外工作,其实它是另一种形式的需求分析。你得想清楚函数该怎么用、输入输出是什么,才能写出测试。这个过程逼你把模糊的想法变成具体的断言。
比如要做一个购物车总价计算,直接写代码可能三下五除二就完事了。但用 TDD,你得先考虑:空购物车是多少?单价10元的东西买两件是不是20?打折商品怎么算?这些边界情况,在测试里一个个列出来,比口头讨论清楚得多。
红-绿-重构:TDD 的节奏感
TDD 有个经典三步:先写测试,让它失败(红);写最简单的代码通过测试(绿);再优化代码结构(重构)。这个循环像跳舞的节拍,让你不会一下子冲进复杂的实现里。
有次我写一个数据导出功能,一开始只支持 CSV。按照 TDD 节奏,我先写了个 test_export_to_csv(),然后实现。后来加 Excel 支持,我就写 test_export_to_excel(),再扩展。每一步都有测试兜底,改起来不慌。不像以前,加个新格式,旧的说不定就崩了。
习惯成自然:从抵触到依赖
刚开始强制自己写测试,确实慢。但三个月后,我发现自己写代码的方式变了。不再是一股脑往 controller 塞逻辑,而是先想“这东西怎么测”。函数变小了,依赖变清晰了,连命名都更准确了——因为你要让测试读起来像句子。
现在我如果看到一段没有测试的代码,反而会觉得不安,像是走在没护栏的高楼上。不是说没测试就不能用,而是少了那份确定性。尤其团队协作时,别人改了代码,我的测试能第一时间喊停。
测试驱动开发不是银弹,但它培养的是一种对代码质量的敏感度。这种编码习惯一旦养成,你会不自觉地追求更清晰的结构、更明确的行为。编程不再是堆砌功能,而是在不断验证中逼近正确。”,"seo_title":"测试驱动开发编码习惯:如何通过TDD提升代码质量","seo_description":"了解测试驱动开发(TDD)如何改变编程习惯,通过实际案例展示TDD在接口验证、边界处理和代码重构中的真实价值。","keywords":"测试驱动开发,编码习惯,TDD,软件开发,单元测试,代码质量"}