在JUnit中Mock subscribe方法内的两个Consumer接口时出现NullPointerException
问题:Mock Mono的subscribe双Consumer时触发NullPointerException
业务代码(ConsumerService.java)
原代码存在语法错误,已标注修正点:
@Autowired ConsumerDao consumerDao; public void insertStatus() { SchedularStatus schedularStatus = new SchedularStatus(); Mono<Object> savedConsumer = consumerDao.save(schedularStatus); // 原代码语法错误:多余的括号和引号,修正后如下 savedConsumer.subscribe( success -> Log.info("consumer data saved"), error -> Log.error("Error while saving schedular data") ); }
测试代码(ConsumerServiceTest.java)
原代码存在拼写错误与Mock逻辑问题:
@ExtendWith(MockitoExtension.class) class ConsumerServiceTest { // 原拼写错误:@InjectMock → @InjectMocks @InjectMocks ConsumerService consumerService; @Mock Mono<Object> mono; @Mock ConsumerDao consumerDao; @Test void testInsertStatus() { Mockito.when(consumerDao.save(any(SchedularStatus.class))).thenReturn(mono); doAnswer(answer -> { Consumer<Object> successConsumer = answer.getArgument(0); // 错误Consumer的参数类型是Throwable,而非Object Consumer<Throwable> errorConsumer = answer.getArgument(1); successConsumer.accept(new Object()); // 传入Throwable类型对象模拟错误场景 errorConsumer.accept(new RuntimeException("模拟保存失败")); return null; }).when(mono).subscribe(any(Consumer.class), any(Consumer.class)); // 必须调用业务方法,原代码遗漏此步骤 consumerService.insertStatus(); // 原拼写错误:Mockto → Mockito Mockito.verify(consumerDao).save(any(SchedularStatus.class)); } }
错误信息
java.lang.NullPointerException : errorConsumer at java.util.Objects.requireNonNull(Objects.java:228) at reactor.core.publisher.Mono.subscribe(Mono.java:4278)
问题分析与修复步骤
- 业务代码语法修正:原代码中subscribe方法的参数写法错误,多了闭合括号和引号,导致编译失败,修正后才能正常运行。
- 测试代码拼写修正:
@InjectMock改为@InjectMocks,Mockito依赖注入注解拼写错误会导致Service无法注入Mock对象。Mockto改为Mockito,拼写错误会触发方法调用失败。
- Mock逻辑修正:
- 错误Consumer的参数类型是
Throwable,原代码传入Object类型对象不符合实际场景,会导致逻辑异常。 - 测试方法必须调用业务方法
consumerService.insertStatus(),否则Mock逻辑不会执行,verify验证也失去意义。
- 错误Consumer的参数类型是
- 更优测试方案:直接Mock Mono容易触发Reactor内部的非空校验,推荐使用Reactor官方的
StepVerifier测试响应式流:@Test void testInsertStatusWithStepVerifier() { // 用Mono.just模拟成功场景 Mockito.when(consumerDao.save(any(SchedularStatus.class))).thenReturn(Mono.just(new Object())); consumerService.insertStatus(); Mockito.verify(consumerDao).save(any(SchedularStatus.class)); // 如需验证日志,可结合自定义日志Appender或ArgumentCaptor实现 }
内容的提问来源于stack exchange,提问作者Ajay Kumar
相关产品推荐
相关产品推荐

