Spring Boot中如何测试REST接口返回整数或浮点数?
你遇到的问题其实很典型:JSON里的数值类型在解析时会保留原始类型(整数是Integer,浮点数是Double),而Hamcrest的is()匹配器会做严格的equals比较——比如Integer(17)和BigDecimal(17)或者Double(17.0)调用equals()都会返回false,导致测试失败。
下面给你两种简单有效的解决方案:
方案一:使用closeTo匹配器(适合浮点数场景)
如果你的数值精度要求不高,可以用closeTo匹配器,它会忽略类型差异,只比较数值是否在指定误差范围内(这里误差设为0就相当于精确匹配)。
修改后的测试代码:
import static org.hamcrest.Matchers.closeTo; // 其他静态导入不变 @ParameterizedTest @MethodSource("createTestData") void testNumbersEndpoint(final String restServiceValue, final double expectedValue) throws Exception { given(restTemplate.getForObject(any(String.class), eq(String.class))).willReturn(restServiceValue); mockMvc.perform(get("/number")) .andExpect(status().isOk()) // 使用closeTo替代is,误差设为0.0 .andExpect(jsonPath("number", closeTo(expectedValue, 0.0))); } private static Stream<Arguments> createTestData() { return Stream.of( Arguments.of("17", 17.0), Arguments.of("12.53", 12.53) ); }
这个方案的好处是不需要改动测试数据的类型,直接复用你原来的double类型预期值即可。
方案二:使用comparesEqualTo匹配器(适合高精度场景)
如果你的业务对数值精度要求很高(比如涉及金额计算),推荐用BigDecimal结合comparesEqualTo匹配器——它会调用compareTo方法做数值比较,只要数值相等就会匹配,不管原始类型是Integer还是Double。
修改后的测试代码:
import static org.hamcrest.Matchers.comparesEqualTo; import java.math.BigDecimal; // 其他静态导入不变 @ParameterizedTest @MethodSource("createTestData") void testNumbersEndpoint(final String restServiceValue, final BigDecimal expectedValue) throws Exception { given(restTemplate.getForObject(any(String.class), eq(String.class))).willReturn(restServiceValue); mockMvc.perform(get("/number")) .andExpect(status().isOk()) // 使用comparesEqualTo匹配BigDecimal数值 .andExpect(jsonPath("number", comparesEqualTo(expectedValue))); } private static Stream<Arguments> createTestData() { return Stream.of( // 注意用字符串构造BigDecimal避免精度丢失 Arguments.of("17", new BigDecimal("17")), Arguments.of("12.53", new BigDecimal("12.53")) ); }
这里要注意用字符串构造BigDecimal,避免直接用double值带来的精度问题(比如new BigDecimal(0.1)其实是一个近似值)。
为什么你之前的尝试无效?
你之前用Number和BigDecimal结合is()匹配器时,is()本质是调用equals()方法,而Integer和BigDecimal的equals()不仅比较数值,还会比较类型,所以Integer(17).equals(new BigDecimal(17))会返回false,导致测试失败。而上面的两种方案都是基于数值比较而非对象相等性比较,所以能兼容不同的数值类型。
内容的提问来源于stack exchange,提问作者stevecross

