← [ BACK_TO_NOTES ]

Java 测试与 JUnit

JUnit 5 如何组织测试、断言与生命周期:把行为锁在可重复反馈里。

#concept #growing #dev #java

[!info] related notes

Java 测试与 JUnit

这个概念为什么出现

没有自动化测试,重构与并发修改只能靠勇气。JUnit 是 Java 生态最常见的测试框架;与构建工具集成后成为 CI 门禁。

[!abstract] 一句话理解 用 JUnit 5 写可独立运行的测试方法,断言期望行为;通过构建工具在 CI 重复执行,锁住回归。

最小可运行示例

场景:定价函数的表意测试

沿用 Gradle 基础 的 JUnit Jupiter 配置(示例固定 5.10.2),保存为 src/test/java/PricingTest.java。Pricing 放在同一测试文件中只是为了演示;实际业务实现应位于 src/main/java。

// src/test/java/PricingTest.java
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;

class PricingTest {
    @Test
    void price_multiplies_units_by_100() {
        assertEquals(200, new Pricing().price(2));
    }
    @Test
    void price_rejects_negative() {
        assertThrows(IllegalArgumentException.class, () -> new Pricing().price(-1));
    }
    @Test
    void price_rejects_int_overflow() {
        assertThrows(ArithmeticException.class, () -> new Pricing().price(Integer.MAX_VALUE));
    }
}

class Pricing {
    int price(int units) {
        if (units < 0) throw new IllegalArgumentException("units");
        return Math.multiplyExact(units, 100);
    }
}

本例约定负数量报 IllegalArgumentException,int 金额溢出报 ArithmeticException。只验证小数值乘法不能发现整数溢出。

构建:

./gradlew test

应在报告中看到 3 个测试。若改用 Maven,需声明 Jupiter 依赖并配置支持 JUnit Platform 的 Surefire,再运行 mvn test;仅有命令退出码为 0 可能是根本没有发现测试。

结合场景再看三个关注点

  1. 测试名描述行为。
  2. 异常也是契约。
  3. 快测优先,IO/DB 放集成测试。

核心概念与准确模型

1. JUnit 5 结构

Platform 提供测试发现/执行基础,Jupiter 提供测试编程模型和引擎。默认每个测试方法使用独立测试实例,@BeforeEach 在每个测试前执行;静态变量和外部资源仍可能共享。@ParameterizedTest 还需要相应参数化测试支持。

2. 断言

  • assertEquals/assertThrows/assertAll

3. 与构建

Maven 常用 Surefire 执行单元测试;Failsafe 需显式配置 integration-test/verify 目标,执行 mvn verify 才能覆盖其完整流程。Gradle 的 test 任务是否执行 Jupiter 取决于依赖及 useJUnitPlatform() 配置。

边界情况与反直觉行为

  1. 默认顺序不应作为依赖;JUnit 可显式配置顺序,但独立测试应支持单独运行和过滤执行。
  2. 共享可变静态状态导致片状失败。
  3. 过度 mock 测不到真实集成。

常见误区

[!warning] 常见误区:只追求覆盖率数字 覆盖率是指标不是目标;断言质量更重要。

工程实践

  1. Arrange-Act-Assert。
  2. 一个行为一个测试焦点。
  3. 测试数据建造器。
  4. CI 失败即阻断合并。

本节总结

  • JUnit 锁行为
  • 与构建/CI 一体
  • 快测与集成分层

自测题

  1. 为什么测试不应依赖执行顺序?
  2. assertThrows 验证什么?
参考答案
  1. 并行与过滤执行会打乱顺序,顺序耦合即脆弱。
  2. 验证调用抛出指定类型或其子类,并返回异常对象;若要验证异常消息,应再对 getMessage() 断言。assertThrows 的 message 参数是断言失败提示,不是期望异常消息;精确类型可用 assertThrowsExactly。

延伸阅读与资料来源

资料类型支撑内容
JUnit 5 User Guide官方用法
创建于 2026/7/15 更新于 2026/10/6
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本