JUnit5中如何断言异常消息不受集合元素顺序影响?
解决JUnit5断言忽略异常消息元素顺序的问题
方法1:提取消息元素转为集合对比
不用断言完整消息,而是提取消息中的缺失元素,转为集合后和预期缺失集合对比(集合对比不关心顺序):
@Test void testSubsetCheck() { Set<String> setA = new HashSet<>(Arrays.asList("b", "c", "d")); Set<String> setB = new HashSet<>(Arrays.asList("a")); IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { Set<String> missing = Sets.difference(setA, setB); Preconditions.checkArgument(missing.isEmpty(), "The strings %s are present in setA but not in setB", String.join(", ", missing)); }); // 从消息中提取元素部分并转成集合 String message = exception.getMessage(); String elementsSection = message.replace("The strings ", "").replace(" are present in setA but not in setB", ""); Set<String> actualMissing = new HashSet<>(Arrays.asList(elementsSection.split(", "))); Set<String> expectedMissing = Sets.difference(setA, setB); assertEquals(expectedMissing, actualMissing); }
方法2:用assertAll验证所有元素都在消息中
直接验证消息包含每个预期缺失元素,不要求顺序:
@Test void testSubsetCheckWithAssertAll() { Set<String> setA = new HashSet<>(Arrays.asList("b", "c", "d")); Set<String> setB = new HashSet<>(Arrays.asList("a")); Set<String> expectedMissing = Sets.difference(setA, setB); IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { Set<String> missing = Sets.difference(setA, setB); Preconditions.checkArgument(missing.isEmpty(), "The strings %s are present in setA but not in setB", String.join(", ", missing)); }); String message = exception.getMessage(); assertAll("验证所有缺失元素都在异常消息中", () -> expectedMissing.forEach(element -> assertTrue(message.contains(element))), () -> assertTrue(message.startsWith("The strings ")), () -> assertTrue(message.endsWith(" are present in setA but not in setB")) ); }
方法3:修改业务代码固定元素顺序
调整异常消息生成逻辑,将缺失元素排序后再拼接,让消息顺序固定:
// 业务代码中修改消息生成 Set<String> missingElements = Sets.difference(setA, setB); List<String> sortedMissing = new ArrayList<>(missingElements); Collections.sort(sortedMissing); Preconditions.checkArgument(missingElements.isEmpty(), "The strings %s are present in setA but not in setB", String.join(", ", sortedMissing));
之后JUnit断言就可以直接匹配固定顺序的消息,不会再因顺序问题失败。
方法4:结合Hamcrest匹配器验证
如果引入Hamcrest库,可用containsInAnyOrder匹配器忽略顺序验证元素:
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.startsWith; import static org.hamcrest.Matchers.endsWith; @Test void testSubsetCheckWithHamcrest() { Set<String> setA = new HashSet<>(Arrays.asList("b", "c", "d")); Set<String> setB = new HashSet<>(Arrays.asList("a")); Set<String> expectedMissing = Sets.difference(setA, setB); IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { Set<String> missing = Sets.difference(setA, setB); Preconditions.checkArgument(missing.isEmpty(), "The strings %s are present in setA but not in setB", String.join(", ", missing)); }); String message = exception.getMessage(); assertThat(message, startsWith("The strings ")); assertThat(message, endsWith(" are present in setA but not in setB")); String elementsPart = message.substring("The strings ".length(), message.length() - " are present in setA but not in setB".length()); assertThat(Arrays.asList(elementsPart.split(", ")), containsInAnyOrder(expectedMissing.toArray(new String[0]))); }
内容的提问来源于stack exchange,提问作者mahb
相关产品推荐
相关产品推荐

