【问题标题】:org.mockito.exceptions.misusing.MissingMethodInvocationException - cannot test exception when method calls other protected methodsorg.mockito.exceptions.misusing.MissingMethodInvocationException - 方法调用其他受保护方法时无法测试异常
【发布时间】:2021-10-01 10:40:54
【问题描述】:

我无法使用 mockito 模拟私有方法,但方法访问说明符可以被打包或保护,所以我这样做了。但即使在那之后,当实际方法包含其他几个受保护的方法调用时,我也无法实现单元测试抛出异常。

来源:

public class ConsumeService {
    
      private DataProcessService dataProcessService;
    
    @JmsListener
      public void getMessage(final Message message) throws InterruptedException {
    
        if (message instanceof TextMessage) {
          TextMessage textMessage = getTextMessage(message);
          try {
            
            Map<String, String> attributes = prepareInfo(textMessage);
            dataProcessService.processRequestData(
                message.getText(), attributes);
            
    
          } catch (JMSException e) {
            log.error("JMSException in message");
          } catch (ResourceAccessException e) {
            log.error("IOException in message");
          }
        } else {
          log.error("message convertion failed!");
        }
      }
     }
     
     TextMessage getTextMessage(final Message message) {
        return (TextMessage) message;
    }
    
    Map<String, String> prepareInfo(TextMessage message) throws JMSException {

    ..
    ..
    
    return result;
  }

测试方法:

    @ExtendWith(MockitoExtension.class)
public class ConsumeServiceTest {

  
     
    @InjectMocks ConsumeService consumeService;
    
    @Mock DataProcessService dataProcessService;
    
    @Test
  public void receiveMessageException() throws ResourceAccessException, JMSException{
    
    TextMessage message = mock(TextMessage.class);
    TextMessage textMessage = mock(TextMessage.class);
    Map<String, String> mockMap = mock(HashMap.class);
    
    when(consumeService.getTextMessage(message)).thenReturn(textMessage); //67 line
    when(consumeService.prepareInfo(textMessage)).thenReturn(mockMap);
    
    Mockito.lenient().
    when(
        dataProcessService.processRequestData(
                textMessage.getText(), mockMap))
    .thenThrow(ResourceAccessException.class);
    
    assertThrows(
            ResourceAccessException.class,
            () -> this.consumeService.getMessage(message));
    }   
            
}

错误:

    org.mockito.exceptions.misusing.MissingMethodInvocationException: 
    when() requires an argument which has to be 'a method call on a mock'.
    For example:
        when(mock.getArticles()).thenReturn(articles);
    
    Also, this error might show up because:
    1. you stub either of: final/private/equals()/hashCode() methods.
       Those methods *cannot* be stubbed/verified.
       Mocking methods declared on non-public parent classes is not supported.
    2. inside when() you don't call method on mock but on some other object.
at com.sample.rest.listner.service.ConsumeServiceTest.receiveMessageException(ConsumeServiceTest.java:67)

我完全不知道如何解决这个问题。我了解错误在于存根,但我不了解如何解决此问题。 其次,一个对类特别有用的 util 方法可以在同一个文件中声明为私有的。我不明白为什么 mockito 不鼓励以这种方式模拟或测试私有/静态方法?有可能吗?我正在使用带有 junit5 的 mockito


更新

修改了测试方法

更新的测试方法:

@Test
  public void receiveMessageException() throws ResourceAccessException, JMSException{

    
    TextMessage message = mock(TextMessage.class);
    
    Mockito.lenient().
    when(
        dataProcessService.processRequestData(
                Mockito.anyString(), Mockito.any(Map.class)))
    .thenThrow(ResourceAccessException.class);
    
    assertThrows(
            ResourceAccessException.class,
            () -> this.consumeService.getMessage(message));
  }

现在错误

org.opentest4j.AssertionFailedError: Expected org.springframework.web.client.ResourceAccessException to be thrown, but nothing was thrown.

我的假设是它在这一行中失败 Map attributes = prepareInfo(textMessage); 我不知道。当我在调试模式下运行测试时,我看到属性是一个空对象。 如何抛出这个 ResourceAccessException

【问题讨论】:

  • 你的测试方法sn-p好像无效,没有声明方法。你能修一下吗?另外,您能否指定哪个行号/when 语句抛出MissingMethodInvocationException
  • sourcesn-p中没有prepareMetaData方法,在test methodsn-p中出现。
  • 对不起,我现在添加了测试方法块,并重命名了方法名称@StefanoCordio

标签: unit-testing junit mockito junit5 spring-jms


【解决方案1】:

虽然原帖中没有具体说明,但我假设MissingMethodInvocationException是由以下人员抛出的:

when(consumeService.getTextMessage(textMessage)).thenReturn(textMessage);

发生这种情况是因为consumeService 不是模拟对象,而是被测对象。如果你想存根ConsumeServiceTest类的方法,你需要spy its instance

备注:

  • It is discouraged to use @Spy and @InjectMocks on the same field。发生这种情况时,可能表明该类违反了单一职责原则,您应该将该类分解为多个独立的类。
  • 如果使用构造函数或 setter 注入,则可以避免 @InjectMocks
  • consumeService.getTextMessage(textMessage) 的存根似乎没有必要,TextMessage 实例已经是consumeService.getMessage 的输入

【讨论】:

  • 我明白你的意思。我对junit5和学习很陌生。但是我已经修改了测试方法,以及我现在嘲笑它的方式,它应该抛出 resourceaccessexception 但仍然失败。
  • 你捕获了 ResourceAccessException 并忽略它。
  • 对不起,我没听懂你的意思..你的意思是说我在异常块中捕获它,这就是为什么它说什么都没有抛出?
  • catch (ResourceAccessException e) { log.error("IOException in message"); } 行正在吞噬异常,这就是为什么测试断言失败,没有抛出任何东西。
猜你喜欢
  • 2014-11-07
  • 1970-01-01
  • 1970-01-01
  • 2013-02-04
  • 2019-12-06
  • 1970-01-01
  • 2012-05-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多