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

JUnit测试中CrudRepository save()返回对象调用方法空指针问题解决

问题分析与解决方案

核心问题

你遇到的NullPointerException原因很明确:

  • OrderEvent是Mock对象,默认所有方法返回null,哪怕你让save()返回这个Mock对象,调用它的getEventId()还是会返回null
  • 你写的when(orderEventHistoryRepository.save(orderEvent).getEventId()).thenReturn(eventId);是错误的Mockito链式打桩写法,Mockito不支持这种直接链式的存根方式

修复步骤

  1. 删除错误的链式打桩代码
    直接删掉这行报错的代码,它完全多余且写法错误:

    when(orderEventHistoryRepository.save(orderEvent).getEventId()).thenReturn(eventId);
    
  2. 给Mock的OrderEvent对象打桩getEventId()方法
    在给Repository的save()方法打桩前,先让你的MockorderEvent对象的getEventId()返回指定的eventId:

    when(orderEvent.getEventId()).thenReturn(eventId);
    
  3. 确保Repository的save()打桩正确
    保留这行代码,让save()返回已经打好桩的orderEvent:

    when(orderEventHistoryRepository.save(any(OrderEvent.class))).thenReturn(orderEvent);
    

额外需要修正的小问题

你的测试代码里还有几个拼写/变量名错误,不修正会直接导致测试失败:

  • myMessage.class 应该改为 MyMessage.class(类名首字母需大写)
  • omsMessage 应该改为 myMessage(变量名要和你定义的一致)
  • 待测试代码里的myMessage myMessage 应该改为 MyMessage myMessage(类名首字母需大写)

修正后的测试方法关键代码片段

@Test
public void processOrderSchedulingSuccessTest() throws Exception {
    
    ConsumerRecord<String, String> consumerRecord = mock(ConsumerRecord.class);
    String messageValue = "{\"action\":\"SCHEDULE_ORDER\", \"payload\":{\"orderId\":\"12345\", \"orderItemIds\": [\"1\", \"2\", \"3\"]}}";
    MyMessage myMessage = mock(MyMessage.class);
    OrderEvent orderEvent = mock(OrderEvent.class);
    Long orderItemId = 1L;
    Long eventId = 67890L;

    when(consumerRecord.value()).thenReturn(messageValue);
    // 修正类名大小写
    when(objectMapper.readValue(consumerRecord.value(), MyMessage.class)).thenReturn(myMessage);

    // 修正变量名
    when(commonUtils.getOrderEvent(myMessage, orderItemId, OrderEventCode.ORDER_SCHEDULED)).thenReturn(orderEvent);
    
    // 给OrderEvent的getEventId打桩
    when(orderEvent.getEventId()).thenReturn(eventId);
    // 让save返回打好桩的orderEvent
    when(orderEventHistoryRepository.save(any(OrderEvent.class))).thenReturn(orderEvent);
    
    assertDoesNotThrow(() -> orderSchedulingService.processOrderScheduling(consumerRecord));
    verify(orderEventHistoryRepository, times(3)).save(any(OrderEvent.class)); // 注意这里应该是times(3),因为orderItemIds有3个元素
    //other assertions
}

注意:原测试里的verify(orderEventHistoryRepository, times(1))要改为times(3),因为待测试代码会循环处理3个orderItemId,调用3次save()。

内容的提问来源于stack exchange,提问作者kickd16

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 09:01:22