5、测试的重要性:自测试代码、单元测试框架、测试驱动开发(TDD)入门

说实话,我见过太多项目死在「不敢改代码」上。

代码越堆越多,谁都不敢动。改一行,怕炸一片。最后整个项目就像个纸糊的巨人,一碰就碎。

为什么会这样?说白了——没有测试

没有测试的代码,就是定时炸弹

我记得刚入行那会儿,带我的老工程师说过一句话,我到现在都记得:

「代码写出来不是本事,能放心改才是本事。」

怎么才能放心改?答案很简单——有测试兜底

你想想看,重构的本质是什么?是「改变结构,不改行为」。那你怎么知道行为没变?靠眼睛看?靠脑子记?都不靠谱。只有测试能告诉你:这次改动有没有把原来的逻辑搞崩。

核心观点:没有测试的重构,不叫重构,叫「碰运气式改代码」。

自测试代码:让代码自己证明自己是对的

什么叫自测试代码?说白了就是——写完代码后,跑一下测试,绿了就是对的,红了就是有问题。

不需要人工去验证。不需要手动点来点去。一切自动化。

我在项目中遇到过最典型的反例:一个支付模块,每次改完都要测试人员手动走一遍流程——下单、支付、退款、对账……一套下来半小时。后来我实在受不了,花了一天时间把核心流程写成自动化测试。从那以后,改完代码跑一遍测试,5分钟搞定。

我的建议:自测试代码不是「锦上添花」,而是「保命符」。尤其是做重构,没有自测试,你根本不敢动。

单元测试框架:选对工具,事半功倍

单元测试框架,说白了就是帮你写测试、跑测试的工具。不同语言有不同的选择:

语言 常用框架 特点
Java JUnit 5 生态成熟,注解驱动
Python pytest 简洁灵活,fixture 强大
JavaScript Jest 零配置,快照测试好用
C# xUnit / NUnit 与 .NET 深度集成

我个人习惯用 JUnit 5 做 Java 项目的单元测试。它的注解体系很清晰,比如 @Test@BeforeEach@DisplayName,写起来很顺手。

举个简单的例子:

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

class CalculatorTest {

    @Test
    @DisplayName("两数相加应该返回正确结果")
    void testAdd() {
        Calculator calc = new Calculator();
        int result = calc.add(2, 3);
        assertEquals(5, result);
    }
}

你看,就这么几行代码,就能保证 add 方法的行为是确定的。以后不管你怎么重构 Calculator 的内部实现,只要这个测试是绿的,你就放心。

测试驱动开发(TDD):先写测试,再写代码

TDD 是什么?三个步骤循环:

  1. 红:先写一个失败的测试
  2. 绿:写最简代码让测试通过
  3. 重构:优化代码,保持测试绿色

我第一次接触 TDD 时觉得这太反直觉了——代码都没写,先写测试?这不是浪费时间吗?

后来真正用了一次才发现,TDD 最大的好处是:让你从一开始就思考「代码该怎么用」,而不是「代码该怎么写」。

注意:TDD 不是银弹。它适合逻辑密集、业务规则明确的模块。对于 UI 交互、外部依赖多的场景,TDD 的性价比会下降。别盲目套用。

我曾经在一个订单系统的折扣模块上用了 TDD。先写测试:

@Test
@DisplayName("满100减20")
void testDiscountOver100() {
    Order order = new Order(120);
    double actual = order.calculateDiscount();
    assertEquals(20.0, actual);
}

然后写最简实现:

public double calculateDiscount() {
    if (totalAmount >= 100) {
        return 20;
    }
    return 0;
}

测试通过后,再考虑要不要抽象成策略模式、要不要支持多种优惠叠加。每一步都有测试保护,改起来心里踏实。

知识体系一览

下面这张图,是我自己梳理的「测试与重构」的关系图。你看一眼就能明白:测试不是独立存在的,它是重构的基石。

重构 测试 自测试代码 单元测试框架 TDD 红 → 绿 → 重构 先写测试再写代码 核心逻辑 测试保障重构安全 → 重构优化代码结构 → TDD驱动设计质量

避坑指南

我曾经犯过一个低级错误:给一个工具类写了 30 个测试,覆盖率 95%,自我感觉良好。结果重构时发现——测试全绿,但业务逻辑还是错了。

为什么?因为测试只测了「方法返回值」,没测「方法之间的交互」。说白了,测试写得太「单元」了,忽略了集成场景。

我的经验:单元测试要写,但别只写单元测试。关键业务流程一定要有集成测试。测试金字塔的每一层都要覆盖到,别只蹲在塔尖。

小结

测试这件事,说白了就是给代码上保险。你愿意花多少时间写测试,就决定了你以后敢不敢改代码。

我个人习惯是:核心逻辑必须 100% 覆盖,边缘逻辑至少 80%。剩下的 20% 靠代码审查和集成测试补上。

记住一句话:没有测试的代码,不是资产,是负债。

公众号:蓝海资料掘金营,微信deep3321