JUnit 4.12本地Eclipse运行出ComparisonFailure但远程执行正常求助
解决JUnit本地JSON对比时的org.junit.ComparisonFailure隐形格式问题
这种情况我之前排查过好几次,明明肉眼看预期和实际的JSON内容完全一致,但JUnit就是报对比失败,还高亮空格位置——核心原因通常是隐形的格式差异:比如换行符、缩进方式、或者JSON序列化的细微配置不同,远程环境和本地Eclipse的环境差异放大了这个问题。下面给你几个实用的排查和解决思路:
1. 检查JSON文件的换行符类型
远程服务器一般用LF(\n)作为换行符,而Windows本地的Eclipse默认可能会把文件保存为CRLF(\r\n)。当你读取expected的JSON文件时带了\r\n,但actual是ObjectMapper生成的默认用LF,就会导致每一行结尾的字符不一样,肉眼看不到但JUnit能检测到。
- 用Notepad++打开你的
signedCasesReportView01.json,查看右下角的换行符标识(比如显示CRLF或LF)。 - 如果和本地序列化的换行符不一致,直接改成一致的(比如改成LF,或者让ObjectMapper生成CRLF)。
2. 统一ObjectMapper的序列化配置
不同环境下ObjectMapper的默认配置可能有差异,比如缩进空格数、是否自动排序键、换行符类型等。你可以显式配置ObjectMapper,让生成的JSON格式完全固定:
ObjectMapper objectMapper = new ObjectMapper(); // 强制统一换行符为LF(和远程一致) objectMapper.configure(JsonGenerator.Feature.WRITE_EOL_AS_LF, true); // 如果需要固定缩进格式(和JSON文件保持一致) objectMapper.enable(SerializationFeature.INDENT_OUTPUT); // 确保键的顺序和JSON文件一致(避免序列化时自动排序) objectMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, false);
这样生成的actual格式就和expected文件完全对齐了,不会出现隐形差异。
3. 用JSON断言库忽略格式差异
如果你的测试只关心JSON的内容和结构,不要求格式完全一致,可以用JSONAssert库来代替JUnit原生的assertEquals,它能自动忽略空格、换行、键顺序这些格式差异:
首先添加Maven依赖:
<dependency> <groupId>org.skyscreamer</groupId> <artifactId>jsonassert</artifactId> <version>1.5.1</version> <scope>test</scope> </dependency>
然后修改测试代码:
import org.skyscreamer.jsonassert.JSONAssert; @Test public void calculateSignedCasesView() throws JsonProcessingException { Case case1 = prepareCase(); getEm().persist(case1); SignedCasesViewFilter filter = new SignedCasesViewFilter( new LinkedHashSet<>(Arrays.asList("testCode")), new Date(0), new Date(0) ); SignedCasesView view = reportService.calculateSignedCasesView(filter); String actual = getObjectMapper().writeValueAsString(view); String expected = readToString("signedCasesReportView01.json"); // 第三个参数设为false,忽略格式差异只对比内容 JSONAssert.assertEquals(expected, actual, false); }
4. 排查隐形字符差异
如果上面的方法都没用,可以把expected和actual的每个字符打印出来,查看ASCII码,找出肉眼看不到的差异:
// 辅助方法:打印字符串每个字符的ASCII码 private void printCharDetails(String str, String label) { System.out.println("=== " + label + " 字符详情 ==="); for (int i = 0; i < str.length(); i++) { char c = str.charAt(i); System.out.printf("第%d位: '%c' (ASCII: %d, 十六进制: 0x%04X)%n", i+1, c, (int)c, (int)c); } } // 在测试中调用 printCharDetails(expected, "expected"); printCharDetails(actual, "actual");
运行后对比输出,就能看到是不是有非打印字符(比如\r、全角空格、零宽空格等)在搞鬼。
内容的提问来源于stack exchange,提问作者Pivoman
相关产品推荐
相关产品推荐

