cloud-native-spring-in-action
cloud-native-spring-in-action copied to clipboard
Chapter 10.4.3 Exercise Solution:Integration test using real world RabbitMQ broker with testcontainers
In chapter 10.4.3, there is a note that presents one exercise for reader. It says:
If you want to test the application against a specific broker (in our case, it would be for RabbitMQ), you can rely on Testcontainers, as you learned in the previous chapter. I’ll leave that up to you as an exercise.
It stuck me for a long time.The solution code provided below that can serve as a reference for others:
real rabbitMQ broker integration test
package com.polarbookshop.dispatcherservice;
import org.junit.jupiter.api.Test;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.RabbitMQContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
import java.util.concurrent.TimeUnit;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Testcontainers
class DispatcherServiceApplicationTests {
@Container
static RabbitMQContainer rabbitMQ = new RabbitMQContainer(DockerImageName.parse("rabbitmq:3.10-management"));
// reference document: https://docs.spring.io/spring-boot/docs/2.7.18/reference/html/howto.html#howto.testing.testcontainers
@DynamicPropertySource
static void rabbitMQProperties(DynamicPropertyRegistry registry){
registry.add("spring.rabbitmq.host", rabbitMQ::getHost);
registry.add("spring.rabbitmq.port", rabbitMQ::getAmqpPort);
registry.add("spring.rabbitmq.username", rabbitMQ::getAdminUsername);
registry.add("spring.rabbitmq.password", rabbitMQ::getAdminPassword);
}
/**
* @SpringBootTest annotation will auto help you to add beans(e.g. RabbitTemplate, RabbitAdmin etc.)
* for more details, see: https://docs.spring.io/spring-amqp/docs/current/reference/html/#spring-rabbit-test
*/
@Autowired
private RabbitTemplate rabbitTemplate;
@Autowired
private RabbitAdmin rabbitAdmin; // you can use AmqpAdmin class too
@Test
void contextLoads() {
}
@Test
void packAndLabel(){
long orderId = 121;
Queue inputQueue = this.rabbitAdmin.declareQueue();
assert inputQueue != null;
Binding inputBinding = new Binding(inputQueue.getName(), Binding.DestinationType.QUEUE, "order-accepted", "dispatcher-service", null);
Queue outputQueue = this.rabbitAdmin.declareQueue();
assert outputQueue != null;
Binding outputBinding = new Binding(outputQueue.getName(), Binding.DestinationType.QUEUE, "order-dispatched", "#", null);
this.rabbitAdmin.declareBinding(inputBinding);
this.rabbitAdmin.declareBinding(outputBinding);
rabbitTemplate.convertAndSend("order-accepted", "dispatcher-service", new OrderAcceptedMessage(orderId));
await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> {
OrderDispatchedMessage message = rabbitTemplate.receiveAndConvert(outputQueue.getName(),
10000, new ParameterizedTypeReference<OrderDispatchedMessage>(){});
assert message != null;
assertThat(message.orderId()).isEqualTo(orderId);
System.out.println("------------------------------------: " + message.orderId());
});
}
}
then you need to add awaitility
dependency and Jackson2JsonMessageConverter
bean for using ParameterizedTypeReference
.
testImplementation "org.awaitility:awaitility:${awaitilityVersion}"
package com.polarbookshop.dispatcherservice;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* this class is created because the ParameterizedTypeReference is needed in DispatcherServiceApplicationTests
*/
@Configuration
public class RabbitMQConfig {
@Bean
public Jackson2JsonMessageConverter messageConverter(){
return new Jackson2JsonMessageConverter();
}
}
Reference:
- https://www.youtube.com/watch?v=9jZInwFtp44&ab_channel=SivaLabs
- https://stackoverflow.com/questions/49816044/connect-to-message-broker-with-spring-cloud-stream-from-test
@ongiant nice solution, thanks a lot for sharing this!
Thanks again for sharing this solution, I have added a link from the repo documentation: https://github.com/ThomasVitale/cloud-native-spring-in-action/blob/main/Guides/testing-rabbitmq-with-testcontainers.md