测试驱动开发-TDD

一、什么是 TDD

TDD (Test‑Driven Development,测试驱动开发) 核心思想:先写测试,再写业务代码,让测试来驱动功能实现,和传统思路反过来。

传统开发:写业务代码 → 写完再写测试 TDD 开发:先写测试用例 (现在一定会报错) → 写最少代码让测试通过 → 重构优化

二、TDD 开发三步法

  1. 红 (Red) :编写一个失败的单元测试。此时功能代码还不存在 / 不完善,运行测试直接报错。
  2. 绿 (Green) :编写最少、最简单的业务代码,让这条测试刚好通过,不追求优雅。
  3. 重构 (Refactor) :优化代码结构、消除重复,保证所有测试依然全部通过

循环往复,每一个小功能都走一遍红‑绿‑重构。

TDD 不是为了多写测试;是用测试来定义需求

三、TDD 优点 & 缺点

优点

  1. 代码天然可测试,高内聚低耦合
  2. 需求通过测试用例显性表达,减少理解偏差
  3. 修改、重构时快速回归,防止改坏原有功能
  4. 自动形成一套完整单元测试集
  5. 逼你从小粒度、简单功能开始实现

缺点

  1. 前期速度慢,要花时间设计测试
  2. 不适合超复杂算法、需求极不稳定频繁大改场景
  3. 需要开发者熟练单元测试框架
  4. 只能保证 "代码满足测试用例",不能保证覆盖全部业务场景

四、Demo:金额折扣工具

需求:

  • 原价大于等于 100,打 9 折
  • 原价小于 100,不打折

TDD 流程演示

1.Red:先写测试

java 复制代码
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class DiscountUtilTest {

    //测试满100打9折
    @Test
    void calcDiscount_priceOver100(){
        DiscountUtil util = new DiscountUtil();
        double pay = util.calc(200);
        assertEquals(180,pay,0.001);
    }

    //小于100不打折
    @Test
    void calcDiscount_priceLess100(){
        DiscountUtil util = new DiscountUtil();
        double pay = util.calc(50);
        assertEquals(50,pay,0.001);
    }
}

🔴报错,DiscountUtil 不存在

2.Green 最简实现先过第一个测试

java 复制代码
public class DiscountUtil {
    public double calc(double price) {
        return 180;
    }
}

第一条测试过,第二条失败,继续完善

3.完善代码,全部用例通过

java 复制代码
public class DiscountUtil {
    public double calc(double price) {
        if(price >=100){
            return price * 0.9;
        }
        return price;
    }
}

✅全部测试通过,再做重构,比如抽常量折扣率

java 复制代码
public class DiscountUtil {
    private static final double DISCOUNT_RATE = 0.9;
    public double calc(double price) {
        if(price >=100){
            return price * DISCOUNT_RATE;
        }
        return price;
    }
}

五、TDD 和普通单元测试区别

TDD 开发后补单元测试
顺序 测试先行 业务代码先行
作用 驱动设计、定义需求、反馈 验证已完成代码正确性
时机 写功能前 写完功能以后
设计影响 倒逼接口设计简单易测 很难改变已经写好的糟糕设计
相关推荐
恒锐丰-罗生18 小时前
SS8103 芯片解析:45V 同步整流降压半桥恒流驱动控制器 大功率光源国产优选 告别低灰闪烁!
驱动开发·嵌入式硬件·硬件工程
小此方19 小时前
Re:Linux系统篇(五十七)线程篇 · 十:基于环形缓冲的生产者消费者模型与信号量
linux·运维·驱动开发
芯片设计-曾工1 天前
YL1621在电池电量显示模块上的替代可行性评估
驱动开发·stm32·单片机·51单片机·硬件工程
木白CPP2 天前
Linux 驱动UART子系统源码分析
linux·运维·服务器·驱动开发·嵌入式硬件·开源软件
恒锐丰-罗生3 天前
小体积大驱动|LTK8833 双通道 H 桥电机驱动芯片,电池供电设备首选动力方案
驱动开发·嵌入式硬件·硬件工程
正点原子6 天前
【正点原子Linux连载】 第十章 pinctrl和gpio子系统实验 摘自【正点原子】ATK-DLRK3568嵌入式Linux驱动开发指南
linux·运维·驱动开发
星马梦缘6 天前
“零一”智能硬件开发挑战赛 宣传稿
驱动开发·智能硬件·活动·培训·科协
小此方7 天前
Re:Linux系统篇(五十四)线程篇 · 七:互斥锁的底层实现原理:从硬件上下文、原子交换指令(Swap)到并发封装实战
linux·运维·驱动开发
芯片设计-曾工8 天前
当精准脉冲遇上清晰视界——CH2205E模块与YL1621的“黄金搭档“
驱动开发·stm32·单片机·51单片机·硬件工程