如何使用Mockito JUnit5为含Lambda表达式的方法编写JUnit测试用例
JUnit测试Lambda内部参数Mock解决方案
核心问题原因
你当前测试用例无法命中objectMapper.writeValueAsString(recordObj.get("value"))的mock规则,主要有两个问题:
- mock参数匹配错误:你定义的mock规则是
Mockito.when(objectMapper.writeValueAsString(Mockito.anyString())).thenReturn("test"),但recordObj.get("value")返回的是Object类型,不是String,规则完全匹配失败 - 没有预先构造合法的
recordObj测试数据:Lambda内部调用了recordObj.get("topic")、recordObj.get("headers")等方法,你没有提前给这些key设置测试值,运行时会直接抛出空指针异常
具体解决步骤
- 调整
writeValueAsString的mock规则,将入参匹配器改为any()适配Object类型入参,也可以针对不同字段返回不同的测试值 - 手动构造测试用的
List<Map<String,Object>> recordMaps,提前填充所有需要用到的key的测试值 - 固定
string2List方法的返回值为你构造的测试数据,避免依赖真实转换逻辑引入额外问题 - 补充
subscribedPackageProcessor相关方法的mock,避免业务逻辑执行报错
修正后测试代码
@Test void applyTest() throws Exception { // 1. 构造测试用MyEvent MyEvent myEvent = new MyEvent(); myEvent.setPackageId("test"); MyRequestWrapper flowRequestWrapper= getMyRequestWrapper(); // 2. 手动构造测试用的recordObj,提前填充所有需要的字段 Map<String,Object> testRecordObj = new HashMap<>(); testRecordObj.put("topic", "test-topic"); // 构造headers,填充需要的trace字段 Map<String, String> testHeaders = new HashMap<>(); testHeaders.put(IdTypeConstants.XTRACEABILITYID, "test-trace-id"); testHeaders.put(IdTypeConstants.XCORRELATIONID, "test-correlation-id"); testRecordObj.put("headers", testHeaders); testRecordObj.put("key", "test-key"); testRecordObj.put("value", "test-value-content"); testRecordObj.put("offset", 123456L); List<Map<String, Object>> testRecordMaps = Collections.singletonList(testRecordObj); // 3. 修正mock规则 // mock string2List返回你构造的测试数据 Mockito.when(objectMapper.readValue(Mockito.anyString(), Mockito.any(TypeReference.class))).thenReturn(testRecordMaps); // 适配Object类型入参,命中Lambda内部的writeValueAsString调用 Mockito.when(objectMapper.writeValueAsString(Mockito.any())).thenReturn("test"); Mockito.when(objectMapper.readValue(Mockito.anyString(), Mockito.eq(MyEvent.class))).thenReturn(myEvent); // mock objectMapper的convertValue方法,避免转换ConsumerRecord报错 Mockito.when(objectMapper.convertValue(Mockito.anyMap(), Mockito.eq(ConsumerRecord.class))).thenReturn(new ConsumerRecord()); // mock processor的process方法,无返回值 Mockito.doNothing().when(subscribedPackageProcessor).processSubscribedPackage(Mockito.eq("test")); // 补充processor的set方法mock,避免空指针 Mockito.doNothing().when(subscribedPackageProcessor).setInput(Mockito.any()); Mockito.doNothing().when(subscribedPackageProcessor).setOutput(Mockito.any()); Mockito.doNothing().when(subscribedPackageProcessor).setPackagesEventList(Mockito.any()); Mockito.doNothing().when(subscribedPackageProcessor).setRequesterType(Mockito.any()); // 4. 执行测试 String response = processESignCompletedEventSvcFlow.apply(flowRequestWrapper); Assertions.assertNotNull(response); }
额外注意事项
如果需要更精准的mock不同字段的返回值,可以用Mockito的thenAnswer方法根据入参内容返回不同值,不需要的话直接用any()适配即可。
内容的提问来源于stack exchange,提问作者Ranjit Soni
相关产品推荐
相关产品推荐

