测试驱动开发基础实践
测试驱动开发基础实践
写代码最怕的不是写错,而是“我以为没问题”。上线前夜才发现自己改了登录逻辑,却把验证码校验连带禁掉,这种事听起来荒唐,做起来却家常便饭。很多时候,我们不是不会写,而是太着急把功能“跑起来”。功能跑起来不等于稳下来,稳下来的前提,是你敢不敢先让代码失败一次,再逼它成功。测试驱动开发,就是把这种“先失败、后成功”的节奏写进日常。它不讲大道理,只讲一条死规矩:没测试,不写实现。

很多人一听测试就头大,觉得是给代码加包袱。其实更像是给自行车装刹车。没刹车也能骑,但下坡时你会犹豫。测试就是那个让你敢踩油门的刹车。它不替你决定方向,但让你知道什么时候该停、什么时候能冲。我刚开始接触时,最不习惯的是节奏慢。想改个小字段,得先写个测试,跑红,改代码,跑绿,再重构。两分钟的事硬生生拖到十分钟。可后来发现,省下的不是这八分钟,而是上线后反复救火的那两小时。
举个简单的例子。我们要做一个订单金额计算的功能:商品价格乘以数量,再减去优惠券,最后加上运费。直觉写法是直接写个函数,传参数,返回结果。写完点运行,看着控制台输出正确数字,心里一松,觉得成了。可这种“看起来对”很脆弱。过两周,有人把优惠券字段改成可空,负数也能传进来,金额算出负数。下单直接崩。这时候再补测试,等于一边修屋顶一边下雨。测试驱动的做法是,先写测试:正常情况、优惠券为零、负数、运费为零。跑,全是红的,因为实现还没写。然后再写最简单的实现,让它们变绿。这个过程逼你提前想边界,而不是等用户替你踩坑。
节奏感是测试驱动最磨人,也最有用的地方。你得学会和失败相处。红灯亮得理直气壮,绿灯亮得小心翼翼。我见过一个团队,把红灯当成“待办清单”。每亮一个红,就说明还有一个场景没被理解清楚。有人甚至故意写一个夸张的失败测试,比如传空字符串、传超长数字,看系统怎么死。死得越难看,理解越深刻。等实现写完,再把那些夸张的测试改成合理的边界。红绿之间来回几次,代码会越来越“懂事”,不再是你以为它懂事,而是它真的只能按你规定的方式运行。
还有一个容易被忽视的收获,是设计上的自省。测试驱动会惩罚“难测”的代码。如果一个函数依赖五个外部服务,测试就得准备五套模拟数据,写到一半你会烦,烦到想拆它。于是函数被拆,依赖被隔离,接口变清晰。很多人说测试驱动让代码变简单,其实不是测试有魔法,而是它逼你面对复杂度。你越想偷懒,测试越难写;测试越难写,你就越不敢偷懒。这种互相较劲,最终让代码变得克制。
当然,它不是万能钥匙。界面频繁变动、探索性原型,或者时间窗口极短的紧急补丁,硬套测试驱动反而拖慢节奏。关键在于场景和取舍。哪怕不全盘采用,也可以把核心逻辑、边界计算、风险模块拎出来,先写测试。测试覆盖率不是目标,理解边界才是。我见过项目覆盖率很高,但测的都是无关痛痒的 get、set,真正出问题的业务规则反而裸奔。这种“数字安全感”最危险。
工具只是配角,心法才是主角。用什么框架不重要,重要的是你愿不愿意先写失败。很多人在这一步卡住,觉得“还没实现怎么测”?其实测试测的不是实现,而是你对外部的承诺。你可以先写一个最简单的断言,哪怕只是判断返回值不为空。只要它红,你就有了方向。红灯亮起来的那一刻,目标就不再模糊。
长期坚持,会发现心态变了。以前改代码像在拆盲盒,不知道会爆出什么;后来像在修钟表,每一步都能听见咬合的声音。出问题不再慌张,因为测试会先开口说话。它会告诉你,是新改动惹的祸,还是旧债务还利息。你甚至会开始感谢那些失败的测试,因为是它们拦下了线上事故。
结语。测试驱动开发听起来像技术方法,其实更像做事习惯。它不承诺不犯错,但承诺错误早暴露;不保证不返工,但保证返工在安全范围内。它用一次次失败,把侥幸变成确定。如果你愿意慢下来,先写测试,再写实现,最后重构,你会发现代码不仅更稳,自己也更稳。稳的不是技术,是面对变化时,心里有底的那一点光。