0

0

JUnit 5 中断言异常消息匹配多个可能顺序的字符串

心靈之曲

心靈之曲

发布时间:2026-01-24 17:11:16

|

210人浏览过

|

来源于php中文网

原创

JUnit 5 中断言异常消息匹配多个可能顺序的字符串

在 junit 5 测试中,当被测方法抛出的异常消息包含动态拼接的集合元素(如 `b, c, d`)且顺序不确定时,直接用 `assertthrows(..., "expected message")` 会因元素遍历顺序不稳定而偶发失败;本文提供两种稳定、原生、无需第三方库的解决方案:固定迭代顺序构造输入数据,或对异常消息进行结构化解析断言。

在使用 Preconditions.checkArgument 等校验逻辑时,若错误消息依赖 Set 的 stream().filter(...).iterator() 遍历结果(如 Joiner.on(", ").join(...)),其输出顺序由底层 Set 实现决定。HashSet 不保证迭代顺序,导致测试中异常消息如 "The strings b, c, d..." 可能变为 "The strings d, b, c...",使基于完整字符串匹配的 assertThrows 断言不可靠。

✅ 方案一:控制输入,确保顺序可预测(推荐)

最简洁、可维护性最高的方式是在测试中主动提供有序集合,而非依赖实现细节。LinkedHashSet 按插入顺序迭代,完全符合需求:

@Test
void funcSubSet_throwsWithConsistentMessage() {
    // 使用 LinkedHashSet 替代 HashSet,保证 filter 后 stream 的顺序稳定
    Set setA = new LinkedHashSet<>(Arrays.asList("a", "b", "c", "d"));
    Set setB = new LinkedHashSet<>(Arrays.asList("a"));

    // 注入到被测对象(假设 funcSubSet 支持参数化或可重写)
    // 或通过重构将集合作为参数传入:funcSubSet(setA, setB)

    IllegalArgumentException ex = assertThrows(
        IllegalArgumentException.class,
        () -> funcSubSet(setA, setB)
    );

    assertEquals(
        "The strings b, c, d are present in setA but not in setB",
        ex.getMessage()
    );
}
? 关键点:此方案要求被测方法支持外部传入集合(即解耦数据构造与业务逻辑),这既是测试友好的设计,也提升了代码内聚性与可读性。

✅ 方案二:解析式断言 —— 对异常消息做语义校验

若无法修改被测方法签名或输入构造方式(如 setA/setB 是私有字段且不可注入),则应放弃“全字符串匹配”,转为校验消息结构 + 关键内容存在性

koly.club
koly.club

一站式社群管理工具

下载
@Test
void funcSubSet_throwsWithCorrectContentRegardlessOfOrder() {
    Exception ex = assertThrows(Exception.class, () -> funcSubSet());

    String msg = ex.getMessage();

    // 校验固定前缀与后缀
    assertTrue(msg.startsWith("The strings "), "Message must start with 'The strings '");
    assertTrue(msg.endsWith(" are present in setA but not in setB"), 
               "Message must end with ' are present in setA but not in setB'");

    // 提取中间变量部分(去除前后固定文本)
    String variablesPart = msg.substring(
        "The strings ".length(),
        msg.length() - " are present in setA but not in setB".length()
    ).trim();

    // 分割并校验每个缺失元素是否都存在(忽略顺序和空格)
    Set expectedMissing = Set.of("b", "c", "d");
    Set actualMissing = Arrays.stream(variablesPart.split(",\\s*"))
                                      .map(String::trim)
                                      .collect(Collectors.toSet());

    assertEquals(expectedMissing, actualMissing, 
                 "Missing elements mismatch: expected " + expectedMissing + ", got " + actualMissing);
}

该方案完全基于 JUnit 5 原生 Assertions,不引入 AssertJ、Hamcrest 等额外依赖,同时具备强健性:即使消息中多出空格、换行或标点微调,只要语义正确即可通过。

⚠️ 注意事项与最佳实践

  • 避免 HashSet 在测试敏感路径中:生产代码中若消息顺序影响用户体验或日志分析,也建议统一使用 LinkedHashSet 或 TreeSet(按字典序)。
  • 不要用 contains() 粗粒度校验:例如 assertTrue(msg.contains("b") && msg.contains("c")) 易受误匹配干扰(如 "ab" 被误认为含 "b"),应先分割再精确比对。
  • 优先重构而非绕过问题:异常消息顺序不可控本质是测试脆弱性的信号,推动将集合构造逻辑外移,比在测试中不断修补断言更可持续。

综上,控制输入顺序是首选策略;结构化解析是兜底方案。二者均立足 JUnit 5 原生能力,兼顾可靠性、可读性与工程可维护性。

相关专题

更多
软件测试常用工具
软件测试常用工具

软件测试常用工具有Selenium、JUnit、Appium、JMeter、LoadRunner、Postman、TestNG、LoadUI、SoapUI、Cucumber和Robot Framework等等。测试人员可以根据具体的测试需求和技术栈选择适合的工具,提高测试效率和准确性 。

439

2023.10.13

java测试工具有哪些
java测试工具有哪些

java测试工具有JUnit、TestNG、Mockito、Selenium、Apache JMeter和Cucumber。php还给大家带来了java有关的教程,欢迎大家前来学习阅读,希望对大家能有所帮助。

299

2023.10.23

Java 单元测试
Java 单元测试

本专题聚焦 Java 在软件测试与持续集成流程中的实战应用,系统讲解 JUnit 单元测试框架、Mock 数据、集成测试、代码覆盖率分析、Maven 测试配置、CI/CD 流水线搭建(Jenkins、GitHub Actions)等关键内容。通过实战案例(如企业级项目自动化测试、持续交付流程搭建),帮助学习者掌握 Java 项目质量保障与自动化交付的完整体系。

19

2025.10.24

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

278

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

212

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1492

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

622

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

572

2024.03.22

c++ 根号
c++ 根号

本专题整合了c++根号相关教程,阅读专题下面的文章了解更多详细内容。

22

2026.01.23

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Go 教程
Go 教程

共32课时 | 4.1万人学习

Go语言实战之 GraphQL
Go语言实战之 GraphQL

共10课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号