Java 模拟void方法返回空指针异常

Java 模拟void方法返回空指针异常,java,unit-testing,mocking,mockito,Java,Unit Testing,Mocking,Mockito,我在尝试对函数调用进行单元测试时遇到了一个问题。调用void方法调用messageProducer.sendMessage()失败,即使它已被存根 请在下面找到我的代码的简化快照。我使用一个doAnswer()存根来模拟void方法(基于前面关于StackOverflow的回答) 我甚至尝试了doThrow()和doNothing()stubbing的其他选项,但在调用stubbed方法时,它们在相同的NPE中也失败了:( 如果有人能提出解决方案/解决方法,我将不胜感激。非常感谢 测试班 //测

我在尝试对函数调用进行单元测试时遇到了一个问题。调用void方法调用
messageProducer.sendMessage()
失败,即使它已被存根

请在下面找到我的代码的简化快照。我使用一个doAnswer()存根来模拟void方法(基于前面关于StackOverflow的回答)

我甚至尝试了
doThrow()
doNothing()
stubbing的其他选项,但在调用stubbed方法时,它们在相同的NPE中也失败了:(

如果有人能提出解决方案/解决方法,我将不胜感激。非常感谢

测试班

//测试类
@RunWith(MockitoJUnitRunner.class)
公共类检索测试{
@Mock
私有消息生产者消息生产者;
 
@mocks
私有MigrationRequestServiceImpl migrationRequestService;
 
@以前
公共void init(){
initMocks(this);
    }
@试验
public void sendRetriggerRequest()引发异常{
//下面两个存根也不行,NPE遇到了!
//doNothing().when(messageProducer).sendMessage(any(),anyLong());
//doThrow(新异常()).doNothing().when(messageProducer).sendMessage(any(),anyLong());
doAnswer(新答案){
公共无效应答(调用锁调用){
对象[]args=invocation.getArguments();
System.out.println(“使用参数调用:+Arrays.toString(args));
返回null;
}
}).when(messageProducer).sendMessage(any(EMSEvent.class),anyLong());
试一试{
//获取空指针异常
migrationRequestService.retriggerRequest(emsRetriggerRequest);
}
捕获(例外情况除外){
失败(例如getMessage());
}
}
在测试实现类时,来自该类的存根方法调用抛出NPE,如代码注释所示

@服务
@交易的
公共类MigrationRequestServiceImpl实现MigrationRequestService{
@自动连线
消息生产者消息生产者;
@凌驾
public void retriggerRequest(EMSRetriggerRequestData EMSRetriggerRequestData)引发EMSException{
//做了很多事情
submitTaskScheduledEventsToQueue(任务列表);
}
私有无效submitTaskScheduledEventsToQueue(列表任务列表){
System.out.println(“调试1…”);
taskList.stream().forEach(任务->{
System.out.println(“调试2…”);
Map detailsMap=newhashmap();
EMSEvent事件=新的EMSEvent(EMSEventType.TASK\u计划);
事件设置详细信息(detailsMap);
LOGGER.info(ContextRetriever.getServiceContext(),ContextRetriever.getRequestContext(),“***重新提交任务:**”+任务.getId());
//****此处提供空指针异常****
messageProducer.sendMessage(事件,eventsConfigProperties.getScheduledEventDelay());
});
System.out.println(“调试3…”);
}
}
自动连接类,该类被注入测试类,其方法是抛出NPE

@服务
公共类消息生成器{
私有静态最终记录器Logger=LoggerFactory.getLogger(MessageProducer.class);
私人最终RabbitTemplate RabbitTemplate;
@自动连线
公共消息制作人(RabbitTemplate RabbitTemplate){
this.rabbitmplate=rabbitmplate;
}   
公共无效发送消息(EMSEvent EMSEvent,长延迟){
//在此向RabbitMQ发送消息的代码
}   
}

如果您只是想捕获参数并以某种方式处理/验证它们,请不要使用doAnswer。Mockito有一个定义的功能,名为
ArgumentCaptor
,专门为此而设计。通过使用它,您不必像现在这样与无效方法讨价还价:

@Mock private MessageProducer messageProducer;

@Captor private ArgumentCaptor<Event> eventCaptor;
@Captor private ArgumentCaptor<Long> longCaptor;

@InjectMocks
private MigrationRequestServiceImpl migrationRequestService;

@Test
public void sendRetriggerRequest() throws Exception {
   // When
   migrationRequestService.retriggerRequest(emsRetriggerRequest);

   // Then
   verify(messageProducer).sendMessage(eventCaptor.capture(), longCaptor.capture());

   Event e = eventCaptor().getValue();
   Long l = longCaptor().getValue();
}
@Mock private MessageProducer MessageProducer;
@捕获者私人辩论捕获者事件捕获者;
@捕获者私人辩论捕获者长捕获者;
@注射模拟
私有MigrationRequestServiceImpl migrationRequestService;
@试验
public void sendRetriggerRequest()引发异常{
//什么时候
migrationRequestService.retriggerRequest(emsRetriggerRequest);
//然后
验证(messageProducer).sendMessage(eventCaptor.capture()、longCaptor.capture());
事件e=eventCaptor().getValue();
Long l=longCaptor().getValue();
}

谢谢Maciej的回答。实际上,我不想对参数做任何事情,我只需要跳过此方法调用。我只是使用doAnswer和一些伪代码,因为doNothing()或doThrow()不适用于此方法

但是,我能够解决这个问题。正在注入mock(MigrationRequestServiceImpl)的类的一个自动连接组件(EventsConfigProperty)在测试类中没有被模拟!感谢@daniu指出这一点

Mockito的堆栈跟踪对调试问题没有太大帮助,它只是在方法调用上出现了一个空指针异常,这让我认为可能还有其他问题

为这个错误道歉,我的错,但是谢谢你,很高兴了解ArgumentCaptor,可能在将来的测试中需要它

必须添加自动连接到MigrationRequestService类的条目

//测试类
@RunWith(MockitoJUnitRunner.class)
公共类检索测试{
@自动连线
事件配置属性事件配置属性;
//其他声明
}

事件配置属性从哪里来?看起来应该是空的。请添加完整的堆栈跟踪。不太清楚NPE从哪里来,哪个对象是空的。感谢@daniu指出这一点。我忽略了模拟ans中给出的自动连接组件