本文介绍了org.mockito.exceptions.misusing.MissingMethodInvocationException - 当方法调用其他受保护的方法时无法测试异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I cannot mock the private methods using mockito, but the method access specifier can be package or protected so i did that. but even after that i cannot achieve unit testing an exception throwing when the actual method contains several other protected method calls.

来源:

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

I absolutely have no clue how to resolve this. I am understanding the error is in stubing but i am not understanding how to fix this.Secondly, an util method specifically useful for a class can be declared as private and in the same file. I do not see why mockito discourage private/static method mocking or testing in that way? Is it possible at all? i am using mockito with junit5

更新

修改了测试方法

更新的测试方法:

@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;属性 = prepareInfo(textMessage);我不确定.当我在调试模式下运行测试时,我看到属性是一个空对象.如何抛出这个ResourceAccessException

My assumption is it is failing in this line Map<String, String> attributes = prepareInfo(textMessage);I am not sure. when i run the test in debug mode, i see attributes is an empty object.How to throw this ResourceAccessException

推荐答案

虽然在原帖中没有说明,但我认为 MissingMethodInvocationException 是由以下原因抛出的:

Although it was not specified in the original post, I assume that the MissingMethodInvocationException is thrown by:

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

发生这种情况是因为 consumeService 不是模拟而是被测对象.如果你想存根 ConsumeServiceTest 类的方法,你需要 监视其实例.

This happens because consumeService is not a mock but the object under test. If you want to stub methods of the ConsumeServiceTest class, you need to spy its instance.

备注:

  • 不鼓励同时使用 @Spy@InjectMocks字段.发生这种情况时,可能表明该类违反了单一职责原则,您应该将该类分解为多个独立的类.
  • @InjectMocks 如果使用构造函数或 setter 注入可以避免.
  • consumeService.getTextMessage(textMessage) 的存根似乎没有必要,TextMessage 实例已经是 consumeService.getMessage 的输入
  • It is discouraged to use @Spy and @InjectMocks on the same field. When this happens, it might be an indication that the class is violating the Single Responsibility Principle and you should break down that class into multiple independent classes.
  • @InjectMocks can be avoided if constructor or setter injection is used.
  • The stubbing of consumeService.getTextMessage(textMessage) seems unnecessary, a TextMessage instance is alredy the input of consumeService.getMessage

这篇关于org.mockito.exceptions.misusing.MissingMethodInvocationException - 当方法调用其他受保护的方法时无法测试异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-03 19:38
查看更多