首页/开发/软件测试速查/单元测试(Unit Test)
测试基础与分层67 条

单元测试(Unit Test)

针对函数、类或模块等小单元的测试,运行快、定位准,是金字塔底层的主要投入方向;通常由开发者在编码期编写与维护。

软件测试速查开发更新于 2026-10-13

单元测试是什么

单元测试针对函数、类或模块等最小可测单元,隔离数据库、网络等外部依赖,用自动化断言快速验证其行为是否符合预期。它处在测试金字塔底层:数量最多、执行最快(毫秒级)、失败定位最直接,通常由开发者随代码一起编写与维护。与集成测试关注模块之间能否协同、端到端测试关注整条业务链路是否可用不同,单元测试聚焦这一小段逻辑本身对不对,因此成为重构与持续集成的第一道安全网。

基本信息

测试对象单个函数/类/模块的最小行为单元
执行特征毫秒级、可每次提交运行、失败直指具体逻辑
运行频率本地保存即跑、每次提交的 CI 阶段必跑
依赖处理用测试替身隔离数据库、网络、时间等外部依赖
常见框架pytest(Python)、JUnit 5(Java)、Vitest/Jest(JS)、NUnit(.NET)
编写角色通常由开发者在编码期同步编写
组织方式与被测代码同仓库,按目录或命名约定区分

典型使用场景

  • 验证分支逻辑:边界值、异常路径等手工难以穷举的组合,用断言逐条固化
  • 重构安全网:改动实现后立刻跑一遍,确认外部行为未被破坏
  • TDD 红绿循环:先写失败用例再写实现,把需求拆成可执行的小步
  • 缺陷回归:修 bug 前先补一条能复现的失败用例,防止回归复发
  • CI 快速门禁:每次提交运行,几分钟内拦住大部分低级错误
  • 行为文档:用例名与断言本身就是代码可读的行为说明

pytest 示例

pytest 示例
# 被测逻辑:取款,余额不足时抛异常
def withdraw(balance, amount):
    if amount > balance:
        raise InsufficientFunds()
    return balance - amount

# 正常路径:余额充足
def test_withdraw_reduces_balance():
    assert withdraw(100, 30) == 70

# 边界:刚好取完全部余额
def test_withdraw_exact_balance():
    assert withdraw(100, 100) == 0

# 异常路径:透支被拒绝且抛出明确异常
def test_withdraw_rejects_overdraft():
    with pytest.raises(InsufficientFunds):
        withdraw(100, 150)

与其他层级对比

维度单元测试集成测试端到端测试
范围单函数/类模块间与外部依赖整条业务链路
速度毫秒级秒到十秒级十秒到分钟级
失败定位直指具体逻辑需判断接口与数据需逐层排查
维护成本低中高且易碎
投入占比金字塔底层最多适量仅关键链路
一个用例只验证一个行为,按准备-执行-断言三段式组织;断言要具体到返回值、异常类型与关键副作用,避免不报错就算过的写法。
对外依赖用 mock/stub/fake 隔离(见测试替身条目),但不要过度:替身过多时测试会与被测实现细节耦合,重构后大量用例失效,反而拖慢迭代。
参数化可把同类输入的多个组合收敛为一个用例(pytest.mark.parametrize),既压缩重复代码又保留每条输入独立的结果;同类输入的边界取舍见边界值分析条目。
衡量单元测试健康度可看四个信号:套件总时长、失败率、断言密度、缺陷修复是否伴随新用例;这些比覆盖率数字更接近真实质量。
用例应独立可重复:连跑两次结果一致、换机器一致、与执行顺序无关;做到这一点通常要求把时钟、随机数改为显式注入再断言。

易错点

  • 用例连真实数据库或网络:执行变慢且不稳定,运行频率下降,最终被移出 CI 流程
  • 只测 getter/setter 等无逻辑代码:覆盖率数字好看,真实缺陷检出能力几乎为零
  • 断言过弱(只断言不抛异常、不断言返回值):用例长期全绿,但无法证明行为正确
  • 过度 mock:测试实际在验证替身调用序列,实现一重构就大面积失败
  • 用例之间互相依赖(前一条造的数据后一条使用):单跑失败、全量偶然通过,排查成本被成倍放大
  • 忽略时间、随机数等隐性依赖:用例在跨天、并发或换机器时偶发失败,需要显式注入可控时钟与种子

数据来源与参考

  • pytest 官方文档(docs.pytest.org)
  • JUnit 5 User Guide(junit.org)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌