首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在MessegePostProcessor中模拟JmsTemplate接口

在MessegePostProcessor中模拟JmsTemplate接口
EN

Stack Overflow用户
提问于 2022-04-02 19:24:48
回答 2查看 386关注 0票数 0

我是Mockito的新手,我面临着一个关于顽固的论点不匹配的问题。

到目前为止,我认为这会很好,因为在我的实现中,jmsTemplate是jmsTemplateService的一个缺陷,所有东西都是通过@Mock和@InjectMocks注入的。

理论上,我是在模拟调用的依赖方法的执行

代码语言:javascript
复制
convertAndSend(String destinationName, final Object message, final MessagePostProcessor postProcessor)

试验的主要部分

代码语言:javascript
复制
Message message = Mockito.mock(Message.class);

MessagePostProcessor messagePostProcessor = (x) -> message;

doNothing()
           .when(jmsTemplate)
           .convertAndSend(queue, obj, messagePostProcessor);

jmsTemplateService.sendMessage(queue, obj);

但是mockito抛出了一个顽固的论点错配错误,这实际上让我明白我没有正确地坚持。

代码语言:javascript
复制
- this invocation of 'convertAndSend' method:
    jmsTemplate.convertAndSend(
    "queueA",
     Obj(),
  com.example.JmsTemplateService$$Lambda$383/0x0000000800dd9440@5fb7183b
);
    -> at com.example.JmsTemplateService.sendMessage(JmsTemplateService.java:64)
 - has following stubbing(s) with different arguments:
    1. jmsTemplate.convertAndSend(
    "queueA",
   Obj(),
   com.example.JmsTemplateServiceTest$$Lambda$382/0x0000000800ddb360@74ad8d05
);

最后一个参数似乎是实际的问题,但我不知道如何在不模拟jmsTemplate依赖项的情况下捕获它。

这是JmsTemplateService.sendMessage的当前实现(字符串队列,obj)

代码语言:javascript
复制
 public void sendMessage(String queue, Object obj) {
        
      try {
           jmsTemplate.convertAndSend(queue, obj, message -> {
           //do stuffs before sending the message
           });
      }catch (Exception e) {
       //handle exception
    }

对于模拟convertAndSend方法可能有什么问题,有什么暗示吗?

非常感谢您的帮助!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-04-02 21:23:12

似乎是最后一个参数是实际问题,但我不知道如何在不模拟jmsTemplate依赖项的情况下捕获它。

实际上,您是在模拟jmsTemplate,否则它会抛出一个异常,因为jmsTemplate变量不是一个模拟。

代码语言:javascript
复制
doNothing()
       .when(jmsTemplate) <- a mock is expected to be used here
       .convertAndSend(queue, obj, messagePostProcessor);

您是对的,因为使用的是不同的实例,所以最后一个参数是实际问题。

第一个实例由lambda在测试中定义:

代码语言:javascript
复制
MessagePostProcessor messagePostProcessor = (x) -> message;

第二个是在执行对jmsTemplate.convertAndSend(..., ..., message -> {...})的调用时用其他lambda定义的。

显然,您得到了该错误,因为您正在验证jmsTemplate.convertAndSend(...)是用您在测试中定义的参数调用的。类似于:

代码语言:javascript
复制
verify(jmsTemplate).convertAndSend(queue, obj, messagePostProcessor);

您可以做的是将any()作为验证中的第三个参数,并期望类似于ArgumentsMatchers.eq(queue)ArgumentsMatchers.eq(obj)的参数作为其他参数:

代码语言:javascript
复制
verify(jmsTemplate).convertAndSend(ArgumentsMatchers.eq(queue), ArgumentsMatchers.eq(obj), any());

Update:测试MessagePostProcessor内部依赖项的可能解决方案

代码语言:javascript
复制
class JmsTemplateServiceTest {

    @Mock
    private JmsTemplate jmsTemplate;

    @Mock
    private Message message;

    @Captor
    private ArgumentCaptor<String> queueCaptor;

    @Captor
    private ArgumentCaptor<String> messageCaptor;

    @Captor
    private ArgumentCaptor<MessagePostProcessor> messagePostProcessorArgumentCaptor;

    @BeforeEach
    void setUp() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    void testJmsTemplateWorksWithCorrectMessagePostProcessor() throws JMSException {
        // Given
        String destinationQueue = "test-queue";
        String testMessage = "test message";

        // When
        doNothing().when(jmsTemplate).convertAndSend(destinationQueue, testMessage, message -> message);

        // Inline dummy implementation that adds an element to a list defined in this test scope
        List<String> stateCustomDependency = new ArrayList<>();
        CustomDependency customDependency = () -> stateCustomDependency.add("Got executed!");

        // Performs service call
        JmsTemplateService jmsTemplateService = new JmsTemplateService(jmsTemplate, customDependency);
        jmsTemplateService.sendMessage(destinationQueue, testMessage);

        // Then verify the service actually invokes the jmsTemplate and capture the arguments passed to it
        verify(jmsTemplate).convertAndSend(queueCaptor.capture(), messageCaptor.capture(), messagePostProcessorArgumentCaptor.capture());

        // Verify values of queue and message
        assertEquals(destinationQueue, queueCaptor.getValue());
        assertEquals(testMessage, messageCaptor.getValue());

        // Verify the MessagePostProcessor instantiated inside the service invokes the lambda dependencies
        MessagePostProcessor messagePostProcessorToVerify = messagePostProcessorArgumentCaptor.getValue();
        messagePostProcessorToVerify.postProcessMessage(message);
        assertEquals(1, stateCustomDependency.size()); // Ensure the CustomDependency was invoked
        assertEquals("Got executed!", stateCustomDependency.get(0)); // Ensure the right String was added by CustomDependency
    }
}

如果您还需要对Message对象调用某些方法,则必须添加类似于when(message.someMethod(...)).thenReturn(...)的语句。

希望能帮上忙!

票数 2
EN

Stack Overflow用户

发布于 2022-04-02 21:17:35

这是因为用于存根的MessagePostProcessor与执行测试方法时传递给JmsTemplate的实际实例不同。

传递给模拟的MessagePostProcessor是一个新实例,它是在测试方法内部创建的,而用于阻塞的实例则是在测试方法之外创建的。它们显然是两个不同的例子。

因为convertAndSend()JmsTemplate中返回了void,所以没有什么需要存根的。在执行测试方法之后,您可以简单地用预期的参数验证它是否被正确执行。类似的事情:

代码语言:javascript
复制
@ExtendWith(MockitoExtension.class)
public class JmsTemplateServiceTest {

    @Mock
    private JmsTemplate jmsTemplate;

    private JmsTemplateService jmsTemplateService;

    @BeforeEach
    public void init() {
        jmsTemplateService = new JmsTemplateService(jmsTemplate);
    }

    @Test
    public void convertAndSendTest() {
        Object someObject = ....;
        jmsTemplateService.sendMessage("queueA", someObject);
        verify(jmsTemplate).convertAndSend(eq("queueA"), eq(someObject), any());
    }

}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71720593

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档