代码之家  ›  专栏  ›  技术社区  ›  Urosh T. Leo Zhao

用Mockito&JUnit测试rabbitmplate#convertAndSend作为lambda

  •  1
  • Urosh T. Leo Zhao  · 技术社区  · 6 年前

    我想测试一下 RabbitTemplate#convertAndSend 方法,如下所示:

    // other stuff omitted for brevity
    
            rabbitTemplate.convertAndSend(myQueue, jsonString, message -> {
            message.getMessageProperties().setPriority(priority);
            return message;
            });
    
    // other stuff omitted for brevity
    

    ArgumentCaptor 用于验证是否使用正确的参数调用了方法。

    @Test
    public void givenMyNotification_whenElementIsSent_thenSetPriorityAndSendValidParameters() {
    
    final ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
    final int expectedPriority = 5;
    final Notification expected = TestUtils.getNotification();
    
    testClass.handleNotification(expected);
    
    verify(rabbitTemplate).convertAndSend(captor.capture(), captor.capture(),
        ArgumentMatchers.eq(MessagePostProcessor.class));
    
    // assertThat...
    ));
    
    }
    

    Wanted:
    <Capturing argument>,
    <Capturing argument>,
    interface org.springframework.amqp.core.MessagePostProcessor
    
    Actual invocation:
    "myQueue",
    "myJson",
    com.example.notification.service.NotificationService$$Lambda$5/73698537@5bda80bf
    

    我试过其他几个来自莫基托和汉克雷斯特的匹配者,但都没用。

    1. 如何测试这种东西?

    2 回复  |  直到 6 年前
        1
  •  1
  •   Loïc Le Doyen    6 年前

    除了最后一个火柴,你几乎都能搞定 ArgumentMatchers.eq(MessagePostProcessor.class)

    你真的问了 莫基托 匹配 参数的类。 您更应该与:

    • 使用的参数的类型 ArgumentMatchers.any(MessagePostProcessor.class)
    • ArgumentMatchers.eq(expectedMessageProcessor) 如果你碰巧有
    • 或者参数捕捉器,如果您确实需要检查参数的值

    但是,在这种特殊情况下,如果使用第一个选项,可能会遇到编译器问题,如 RabbitTemplate 类有两个类似的方法:

    • convertAndSend(字符串、字符串、对象)
    • convertAndSend(字符串、对象、消息后处理器)

    要解决此问题,可以强制第二个参数的类型如下所示:

    Mockito.verify(rabbitTemplate).convertAndSend(captor.capture(), (Object) captor.capture(),
                Mockito.any(MessagePostProcessor.class));
    

    或者更好,有两个不同的 ArgumentCaptor 对于两个不同的参数:

    ArgumentCaptor<String> routingKeyCaptor = ArgumentCaptor.forClass(String.class);
    ArgumentCaptor<Object> messageCaptor = ArgumentCaptor.forClass(Object.class);
    
    ...
    
    verify(rabbitTemplate).convertAndSend(routingKeyCaptor.capture(), messageCaptor.capture(), any(MessagePostProcessor.class));
    

    希望这有帮助!

        2
  •  0
  •   Dovmo    6 年前

    我想这完全取决于你在做什么 真正地 尝试测试它能增加什么样的业务价值。

    1. RabbitTemplate 它自己?春季回购对此有测试,但我认为你不需要这么做。
    2. 你在测试弹簧吗 Service 你要确认有人发了信息吗?
    3. 要确保邮件到达目的地吗?

    对于(1),有一些例子正好说明了您在 Spring Framework here in their unit tests for the RabbitTemplate .

    例如,验证 ConnectionFactory 事实上 created a channel :

        txTemplate.execute(status -> {
            template.convertAndSend("foo", "bar");
            return null;
        });
        txTemplate.execute(status -> {
            template.convertAndSend("baz", "qux");
            return null;
        });
        verify(mockConnectionFactory, Mockito.times(1)).newConnection(any(ExecutorService.class), anyString());
        // ensure we used the same channel
        verify(mockConnection, times(1)).createChannel();
    

    兔模板 我个人喜欢对调用方法时使用的参数进行测试,或者使用 Mockito#any

    仅供参考,在断言方面,我还要看一下 AssertJ

    https://www.testcontainers.org/ (如果你用的是docker),我还没查出来,但可能有JUnit @Rule 创建RabbitMQ代理(我必须检查一下)。我做这种事已经有一年了 ActiveMQ Artemis 它会很快为您启动一个代理,您可以使用排队的消息。