You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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)

问题分析与修复步骤

  1. 业务代码语法修正:原代码中subscribe方法的参数写法错误,多了闭合括号和引号,导致编译失败,修正后才能正常运行。
  2. 测试代码拼写修正:
    • @InjectMock 改为 @InjectMocks,Mockito依赖注入注解拼写错误会导致Service无法注入Mock对象。
    • Mockto 改为 Mockito,拼写错误会触发方法调用失败。
  3. Mock逻辑修正:
    • 错误Consumer的参数类型是Throwable,原代码传入Object类型对象不符合实际场景,会导致逻辑异常。
    • 测试方法必须调用业务方法consumerService.insertStatus(),否则Mock逻辑不会执行,verify验证也失去意义。
  4. 更优测试方案:直接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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 02:05:34