【SpringBoot】31 核心功能 - 单元测试 - JUnit5 单元测试中的断言机制——验证你的代码是否按预期执行了

文章目录


前言

大家好,我是正在写单元测试的"小开发"一枚。最近在项目里用 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 要测异常,得用 @RuleExpectedException,很麻烦。

现在 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")
        );
    }
}

好了,今天的分享就到这里。希望这篇"边学边写"的博客对你有帮助。如果你也在写测试,欢迎留言交流你的断言技巧!

相关推荐
l1t4 小时前
编译SQLite 3.51源码并体验新功能
单元测试·sqlite·duckdb
计算机学姐4 小时前
基于SpringBoot的高校社团管理系统【协同过滤推荐算法+数据可视化】
java·vue.js·spring boot·后端·mysql·信息可视化·推荐算法
编啊编程啊程10 小时前
【029】智能停车计费系统
java·数据库·spring boot·spring·spring cloud·kafka
hashiqimiya10 小时前
springboot后端的接口headers
java·spring boot·后端
ss27310 小时前
Springboot + vue 医院管理系统
vue.js·spring boot·后端
披着羊皮不是狼12 小时前
Spring Boot——从零开始写一个接口:项目构建 + 分层实战
java·spring boot·后端·分层
Spirit_NKlaus14 小时前
Springboot自定义配置解密处理器
java·spring boot·后端
用户37779672109617 小时前
BeanPostProcessor失效?
spring boot