JUnit 是 Java 最主流的单元测试框架,Spring Boot 项目里 spring-boot-starter-test 自带它。这篇快速入门:怎么写测试、怎么断言、测试的生命周期。
一、解决什么问题:给代码"上保险"
单元测试 = 给单个方法/类写"验证用例"——输入一组数据,断言输出符合预期。好处:
- 改代码不怕改坏:回归测试自动告诉你哪坏了
- 写代码时就想清楚边界:测试逼你考虑空值、异常等场景
二、引入依赖
Spring Boot 项目已经自带(spring-boot-starter-test)。纯 Java 项目加:
xml
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>三、第一个测试
java
// 被测类
public class Calculator {
public int add(int a, int b) { return a + b; }
public int divide(int a, int b) { return a / b; }
}java
import org.junit.jupiter.api.*;
class CalculatorTest {
private Calculator calc;
@BeforeEach // 每个测试方法前执行
void setUp() {
calc = new Calculator();
}
@Test
void add_两个数相加() {
assertEquals(5, calc.add(2, 3)); // 断言:期望 5,实际结果
}
@Test
void divide_除零抛异常() {
assertThrows(ArithmeticException.class, () -> calc.divide(1, 0));
}
}运行方式:IDEA 里点方法/类左边的绿色三角,或 mvn test。
四、核心断言
| 断言 | 作用 |
|---|---|
assertEquals(期望, 实际) | 相等(基本类型/对象) |
assertTrue / assertFalse | 布尔判断 |
assertNull / assertNotNull | 空判断 |
assertThrows(异常类, 表达式) | 断言抛出指定异常 |
assertAll(...) | 多个断言一起执行,全过才过 |
五、测试生命周期
测试有 4 个"钩子"注解,分两对:@All(类级,只执行一次) 和 @Each(方法级,每个测试都执行)。
| 注解 | 执行时机 | 典型用途 |
|---|---|---|
@BeforeAll / @AfterAll | 整个类所有测试前/后,只执行一次(必须静态方法) | 初始化/关闭连接池、数据库连接 |
@BeforeEach / @AfterEach | 每个测试方法前/后各执行一次 | 准备/清理单条测试数据 |
执行顺序(一个类有 3 个测试时):
用一个能直接跑的类看真实输出(3 个测试方法 + 计数器):
java
class OrderServiceTest {
static int initCount = 0; // 统计 @BeforeAll/@AfterAll 执行次数
@BeforeAll
static void initAll() { // 只执行 1 次:整个类开始前
initCount++;
System.out.println("[BeforeAll] 第 " + initCount + " 次:初始化连接池");
}
@AfterAll
static void tearDownAll() { // 只执行 1 次:整个类结束后
initCount++;
System.out.println("[AfterAll] 第 " + initCount + " 次:关闭连接池");
}
@BeforeEach
void init() { // 每个测试前都执行
System.out.println(" [BeforeEach] 准备数据");
}
@AfterEach
void cleanup() { // 每个测试后都执行
System.out.println(" [AfterEach] 清理数据");
}
@Test
void test1() { System.out.println(" [测试1] 执行"); }
@Test
void test2() { System.out.println(" [测试2] 执行"); }
@Test
void test3() { System.out.println(" [测试3] 执行"); }
}运行输出(javac + JUnit ConsoleLauncher 实跑验证,4 tests successful):
[BeforeAll] 第 1 次:初始化连接池 ← ① 整个类开始前,只 1 次
[BeforeEach] 准备数据
[测试1] 执行
[AfterEach] 清理数据
[BeforeEach] 准备数据 ← ② 每个测试前都来一遍
[测试2] 执行
[AfterEach] 清理数据
[BeforeEach] 准备数据
[测试3] 执行
[AfterEach] 清理数据
[AfterAll] 第 2 次:关闭连接池 ← ③ 整个类结束后,只 1 次核心区别一句话:@All 管"整个类只做一次的事"(重资源,建一次省反复建);@Each 管"每个测试都要的事"(数据准备/清理,保证测试相互独立——A 测试留下的数据不会污染 B 测试)。
小结
- JUnit 5 是 Java 单元测试标准,Spring Boot 自带
- 核心:
@Test+ 断言方法(assertEquals/assertThrows 等) - 生命周期:@BeforeAll(一次)/ @BeforeEach(每个前)
- 一个方法一个测试,测正常 + 测异常边界
想了解怎么用 Mockito 模拟依赖(测 Service 不依赖真实 DB),看「Mockito 测试替身」(文章整理中)。
