当前位置: 首页 > 知识库问答 >
问题:

RabbitListenerTestHarness在侦听器中注入实际对象

解晟睿
2023-03-14

场景:Junit用于微服务,它侦听队列并在数据提取后发布到rabbitMQ中的exchange。

问题:

RabbitListenerTestHarness正在单独为Rabbit Listener类创建模拟对象,正在为Listener自动连接组件实例化实际对象

我找不到手动向听众注入模拟豆的方法。这导致JUnit在JUnit执行期间将测试消息发布到微服务中配置的实际队列。

解决方法:使用rabbit测试项目的唯一方法是配置测试交换,以便在Junit执行期间发布消息。

问:我想了解,是否有更好的方法为兔子的监听器编写Junit。我还想了解是否有一种方法可以将模拟对象注入到兔子监听器的自动连线组件中。

示例代码段:

兔子侦听器类

@RabbitListener(id = "id", bindings = @QueueBinding(value = @Queue(value = "sampleQueue", durable = "true", autoDelete = "false"),key = "sampleRoutingKey", exchange = @Exchange(value = "sampleExchange", durable = "true", ignoreDeclarationExceptions = "true", type = EXCHANGE_TYPE)))
public void getMessageFromQueue(@Payload EventModel event) throws ListenerExecutionFailedException, JAXBException {
    dataExporterService.exportDataAndPostToRabbit(event);
}

服务类

@Autowired
DataExtractorRepository dataExtractorRepository;
@Autowired
DataPublihserRepository dataPublisherRepo;
public void exportDataAndPostToRabbit(EventModel event) throws JAXBException {
        dataPublisherRepo.sendMessageToExchange(dataExtractorRepository.extractOrderData(event), exchangeName, routingKeyValue);
}

DataPublihserRepository有RabbitTem板内部自动生成。DataExtractorRepository内部连接到DB以检索消息。

测试班

@Autowired
private RabbitListenerTestHarness harness;

@Autowired
private RabbitTemplate rabbitTemplate;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
DataExporterController = this.harness.getSpy("id");
}

@Test
public void shouldReceiveMessage() throws Exception {
LatchCountDownAndCallRealMethodAnswer answer = new LatchCountDownAndCallRealMethodAnswer(1);
doAnswer(answer).when(DataExporterController).getMessageFromQueue(any(EventModel.class));
rabbitTemplate.convertAndSend("sampleExchange", "sampleRoutingKey", createMessage());
assertTrue(answer.getLatch().await(10, TimeUnit.SECONDS));
verify(DataExporterController, times(1)).getMessageFromQueue(any(OrderEventsModel.class));
verify(orderDataExporterController, times(1)).getMessageFromQueue(any(OrderEventsModel.class));
}

 private Message createMessage() {
        String inputObject = "{\"id\":12345}";
        MessageProperties props = MessagePropertiesBuilder.newInstance().setContentType(MessageProperties.CONTENT_TYPE_JSON).build();
        return new Message(inputObject.getBytes(), props);
}

共有1个答案

乐正晟
2023-03-14

该线束用于验证侦听器是否在集成测试中接收到数据。要对侦听器进行单元测试,请调用其onMessage方法。

例如,使用Mockito,给定

public class MyListener {

    @Autowired
    private SomeService service;

    @RabbitListener(id = "myListener", queues = "foo")
    public void listen(Foo foo) {
        this.service.process(foo);
    }

}

public interface SomeService {

    void process(Foo foo);

}

然后呢

@RunWith(SpringRunner.class)
public class So53136882ApplicationTests {

    @Autowired
    private RabbitListenerEndpointRegistry registry;

    @Autowired
    private SomeService service;

    @Test
    public void test() throws Exception {
        SimpleMessageListenerContainer container = (SimpleMessageListenerContainer) this.registry
                .getListenerContainer("myListener");
        ChannelAwareMessageListener listener = (ChannelAwareMessageListener) container.getMessageListener();
        Message message = MessageBuilder.withBody("{\"bar\":\"baz\"}".getBytes())
                .andProperties(MessagePropertiesBuilder.newInstance()
                        .setContentType("application/json")
                        .build())
                .build();
        listener.onMessage(message, mock(Channel.class));
        verify(this.service).process(new Foo("baz"));
    }

    @Configuration
    @EnableRabbit
    public static class config {

        @Bean
        public ConnectionFactory mockCf() {
            return mock(ConnectionFactory.class);
        }

        @Bean
        public MessageConverter converter() {
            return new Jackson2JsonMessageConverter();
        }

        @Bean
        public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory() {
            SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
            factory.setConnectionFactory(mockCf());
            factory.setMessageConverter(converter());
            factory.setAutoStartup(false);
            return factory;
        }

        @Bean
        public MyListener myListener() {
            return new MyListener();
        }

        @Bean
        public SomeService service() {
            return mock(SomeService.class);
        }

    }

}

请注意,容器工厂不会启动侦听器容器。

为了测试发布,注入一个mockRabbitOP,它由RabbitTemboard实现。

例如,给定

public class SomeServiceImpl implements SomeService {

    @Autowired
    private RabbitOperations rabbitOperations;

    @Override
    public void process(Foo foo) {
        this.rabbitOperations.convertAndSend(
                "someExchange", "someRoutingKey", new Foo(foo.getBar().toUpperCase()));
    }

}

@Bean
public SomeService service() {
    return new SomeServiceImpl();
}

@Bean
public RabbitOperations rabbitTemplate() {
    return mock(RabbitOperations.class);
}

然后呢

@Test
public void test() throws Exception {
    SimpleMessageListenerContainer container = (SimpleMessageListenerContainer) this.registry
            .getListenerContainer("myListener");
    ChannelAwareMessageListener listener = (ChannelAwareMessageListener) container.getMessageListener();
    Message message = MessageBuilder.withBody("{\"bar\":\"baz\"}".getBytes())
            .andProperties(MessagePropertiesBuilder.newInstance()
                    .setContentType("application/json")
                    .build())
            .build();
    listener.onMessage(message, mock(Channel.class));
    verify(this.rabbitTemplate).convertAndSend("someExchange", "someRoutingKey", new Foo("BAZ"));
}
 类似资料:
  • 问题内容: 我需要将Spring依赖项注入到JPA实体侦听器中。我知道我可以使用@Configurable和Spring的AspectJ weaver作为javaagent来解决此问题,但这似乎是一个棘手的解决方案。还有其他方法可以完成我想做的事情吗? 问题答案: 另一个技巧是用静态方法实现实用程序类,该实用程序类可帮助您不仅在托管类中在任何地方使用Spring Bean:

  • 我试图为我们现有的laravel站点(laravel 5.2)的注销功能添加一些逻辑,但它不像登录那样简单。 客户端的现有注销工作正常,但我只想向我的Cognoto实例添加一个调用,以将用户注销他们的Cognoto会话。基本上,当用户单击logout时,我想让他们从网站上注销,就像以前一样,但也要点击我的cognito注销endpoint 我的困惑来自这样一个事实,即auth的现有路由和控制器并不

  • 问题内容: 我当时在上网,但找不到很好的信息。我试图在每次运行应用程序时检测按键。我正在使用JavaFX并将其与FXML一起运行。我尝试了很多事情,但没有任何效果。请帮我。 问题答案: 您应该签出Ensemble示例。这是关键的侦听器代码。

  • 我正在使用Realex Payments的HPP API开发一个卡支付页面,其中包含一个iFrame,用于托管Realex页面。在Realex请求表单上,我将字段HPP_POST_维度和HPP_POST_响应设置为我的URL,如下所示: 付款页: www.example.com/account/payment.html 隐藏字段值用于在HPP页面大小更改和事务完成时,使用事件侦听器将数据从Real

  • 虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过watch选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。例如: <div id="watch-example"> <p> Ask a yes/no question: <input v-model="question">

  • 1. 前言 本节介绍侦听器 watch 的使用方法。包括什么是侦听器,侦听器的特点,以及如何对不同类型的数据进行监听。其中重点掌握对不同类型的数据如何使用侦听器,了解它之后,在才能在之后的日常开发中熟练运用。 2. 慕课解释 Vue 提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:侦听属性。 — 官方定义 侦听器 watch 是 Vue 提供的一种用来观察和响应 Vue 实例上的数据