文章目录
-
- 前言
- 一、什么是断言?为什么它这么重要?
- 二、简单断言:最常用的几个
-
- [1. `assertEquals`](#1.
assertEquals) - [2. `assertNotEquals`](#2.
assertNotEquals) - [3. `assertSame` / `assertNotSame`](#3.
assertSame/assertNotSame) - [4. `assertTrue` / `assertFalse`](#4.
assertTrue/assertFalse) - [5. `assertNull` / `assertNotNull`](#5.
assertNull/assertNotNull)
- [1. `assertEquals`](#1.
- 三、数组断言:对比数组是否一致
- 四、组合断言:一次性验证多个条件
- 五、异常断言:测试代码是否抛出预期异常
- 六、超时断言:防止测试卡死
- 七、快速失败:直接让测试失败
- [八、实战案例:测试 Redis 连接](#八、实战案例:测试 Redis 连接)
- 九、总结:断言是测试的灵魂
- 十、写在最后
前言
大家好,我是正在写单元测试的"小开发"一枚。最近在项目里用 JUnit5 做测试,发现了一个特别重要的东西------断言(Assertions)。一开始我也觉得"不就是判断一下结果对不对吗?",但真正用起来才发现,它不只是"判断",而是整个测试逻辑的"大脑"。
今天就来和大家聊聊我在实际开发中是如何一步步理解并使用 JUnit5 的断言机制 的。我会像平时写代码一样,一边讲思路,一边贴代码,顺便看看测试效果,保证你一看就懂!
一、什么是断言?为什么它这么重要?
先说点基础的。
断言(assertions),是单元测试的核心部分。它的作用是:验证你的代码是否按预期执行了。
比如你写了个加法函数 add(a, b),你期望 add(2, 3) 返回 5。那你就得用断言去检查这个返回值是不是真的等于 5。
如果等于 → 测试通过 ✅
如果不等于 → 测试失败 ❌
这就是断言的作用。
在 JUnit5 中,所有断言都是静态方法,来自 org.junit.jupiter.api.Assertions 类。我们接下来一个个来看。
二、简单断言:最常用的几个
这是最基础的断言,用来做简单的值判断。
1. assertEquals
判断两个值是否相等。
java
@Test
@DisplayName("简单断言:相等")
public void testEquals() {
int result = 2 + 3;
assertEquals(5, result);
}
✅ 效果:如果 result 是 5,测试通过;否则报错。
2. assertNotEquals
判断两个值是否不相等。
java
@Test
@DisplayName("简单断言:不相等")
public void testNotEquals() {
int result = 2 + 3;
assertNotEquals(6, result);
}
✅ 如果结果不是 6,就通过;如果是 6 就失败。
3. assertSame / assertNotSame
判断两个引用是否指向同一个对象。
java
@Test
@DisplayName("引用相同")
public void testSame() {
String str1 = "hello";
String str2 = str1;
assertSame(str1, str2); // 会通过,因为是同一个对象
}
@Test
@DisplayName("引用不同")
public void testNotSame() {
String str1 = "hello";
String str2 = new String("hello");
assertNotSame(str1, str2); // 会通过,虽然内容一样,但对象不同
}
⚠️ 注意:assertSame 看的是内存地址,不是内容!
4. assertTrue / assertFalse
判断布尔值。
java
@Test
@DisplayName("布尔断言")
public void testBoolean() {
assertTrue(2 > 1);
assertFalse(2 < 1);
}
5. assertNull / assertNotNull
判断对象是否为 null。
java
@Test
@DisplayName("null 断言")
public void testNull() {
String str = null;
assertNull(str);
String notNull = "abc";
assertNotNull(notNull);
}
三、数组断言:对比数组是否一致
有时候我们需要比较两个数组是否相等,这时候用 assertArrayEquals。
java
@Test
@DisplayName("数组断言")
public void array() {
int[] arr1 = {1, 2};
int[] arr2 = {1, 2};
assertArrayEquals(arr1, arr2);
}
✅ 只要顺序和内容都一样,就会通过。
如果你改成 {2, 1},就会失败。
四、组合断言:一次性验证多个条件
有时候你想一次检查多个断言,可以用 assertAll。
java
@Test
@DisplayName("组合断言")
public void assertAll() {
assertAll(
() -> assertEquals(2, 1 + 1),
() -> assertTrue(1 > 0),
() -> assertNotNull("hello")
);
}
💡 优点:即使其中一个失败,其他还会继续执行(不会中断),你可以看到所有问题。
👉 比如上面如果第一个断言失败了,后面两个也会跑完,方便调试。
五、异常断言:测试代码是否抛出预期异常
以前用 JUnit4 要测异常,得用 @Rule 或 ExpectedException,很麻烦。
现在 JUnit5 有 assertThrows,超简单!
java
@Test
@DisplayName("异常断言")
public void testException() {
Throwable exception = assertThrows(
ArithmeticException.class,
() -> {
int result = 10 / 0;
}
);
assertTrue(exception.getMessage().contains("/ by zero"));
}
✅ 这个测试会成功,因为我们确实抛出了 ArithmeticException。
如果没抛异常,或者抛了别的异常,就会失败。
六、超时断言:防止测试卡死
有些方法可能因为网络或 IO 操作太慢,导致测试一直挂住。
我们可以设置超时时间。
java
@Test
@DisplayName("超时断言")
public void timeoutTest() {
Assertions.assertTimeout(Duration.ofMillis(1000), () -> {
Thread.sleep(500); // 这个不会超时
});
}
✅ 如果方法执行超过 1 秒,就会抛异常。
你可以试试把 sleep(500) 改成 sleep(1500),然后看测试失败。
七、快速失败:直接让测试失败
有时候你想手动让测试失败,比如某个条件不满足时强制失败。
用 fail() 方法:
java
@Test
@DisplayName("快速失败")
public void shouldFail() {
fail("This should fail");
}
✅ 这个测试一定会失败,并输出提示信息。
这在写测试框架或模拟某些边界情况时很有用。
八、实战案例:测试 Redis 连接
我之前遇到一个问题,测试 Redis 连接的时候,连接失败了,但测试没报错,只打印了日志。
比如这样:
java
@Test
@DisplayName("测试 Redis")
public void testRedis() {
try {
redisTemplate.opsForValue().get("test");
} catch (Exception e) {
System.err.println("Redis 连接失败:" + e.getMessage());
}
}
但这只是打印,测试依然通过了!
这不是我们想要的。
所以我们应该用断言来捕获异常:
java
@Test
@DisplayName("测试 Redis 连接异常")
public void testRedisConnection() {
assertThrows(
RedisConnectionFailureException.class,
() -> redisTemplate.opsForValue().get("test")
);
}
或者更通用一点:
java
@Test
@DisplayName("Redis 连接应失败")
public void testRedisFail() {
Throwable exception = assertThrows(Exception.class, () -> {
redisTemplate.opsForValue().get("test");
});
assertTrue(exception.getMessage().contains("connection"));
}
这样,一旦连接失败,测试就会明确失败,而不是默默忽略。
九、总结:断言是测试的灵魂
| 断言类型 | 用途 |
|---|---|
assertEquals, assertNotEquals |
检查值是否相等 |
assertSame, assertNotSame |
检查引用是否相同 |
assertTrue, assertFalse |
检查布尔条件 |
assertNull, assertNotNull |
检查 null |
assertArrayEquals |
检查数组是否相等 |
assertAll |
组合多个断言 |
assertThrows |
检查是否抛出特定异常 |
assertTimeout |
设置超时时间 |
fail() |
手动让测试失败 |
这些断言方法就像"裁判",帮你判断代码行为是否符合预期。
十、写在最后
刚开始写测试时,我也只是简单地用 assertEquals,后来才慢慢发现,好的断言能让测试更清晰、更健壮。
比如:
- 用
assertThrows而不是 try-catch - 用
assertAll避免中途失败中断 - 用
assertTimeout防止测试卡住
这些都是"细节控"的体现,但正是这些细节,决定了你的测试是否可靠。
所以,别小看断言,它是你代码质量的"守护神"。
📌 附:完整测试类示例
java
import org.junit.jupiter.api.*;
import java.time.Duration;
class MyTests {
@Test
@DisplayName("简单断言")
public void simpleAssert() {
assertEquals(5, 2 + 3);
assertTrue(1 > 0);
assertNotNull("hello");
}
@Test
@DisplayName("异常断言")
public void exceptionAssert() {
assertThrows(ArithmeticException.class, () -> {
int x = 10 / 0;
});
}
@Test
@DisplayName("超时断言")
public void timeoutAssert() {
Assertions.assertTimeout(Duration.ofMillis(1000), () -> {
Thread.sleep(500);
});
}
@Test
@DisplayName("组合断言")
public void allAssert() {
assertAll(
() -> assertEquals(2, 1 + 1),
() -> assertTrue(true),
() -> assertNotNull("test")
);
}
}
好了,今天的分享就到这里。希望这篇"边学边写"的博客对你有帮助。如果你也在写测试,欢迎留言交流你的断言技巧!