I need to mock a RabbitMQ in my unit Test

后端 未结 3 2044
-上瘾入骨i
-上瘾入骨i 2021-02-07 19:17

I am using a RabbitMQ in my project.

I have in my consumer the code of the client part of rabbitMQ and the connection need a tls1.1 to connect with the real MQ.

相关标签:
3条回答
  • 2021-02-07 20:12

    So here is how i did it, some stuffs might be here and there in process of hiding the necessary class implementation details, but you would get a hint! :)

    • assumption for unit test:
      • RMQ is working fine and data send to it would be pushed in queue
      • Only thing to be tested is if the data generated is correct or not
      • and whether the call to RMQs send() is happening or not!

     public class SomeClassTest {
            private Config config;
            private RmqConfig rmqConfig;
            private static final ObjectMapper mapper = new ObjectMapper();
            private JasperServerClient jasperServerClient;
        //    @Mock
            @InjectMocks
            private RabbitMQProducer rabbitMQProducer;
            private Connection phoenixConnection;
            private String targetNotificationMessage;
            SomeClass someClassObject;
    
            @Before
            public void setUp() {
    
                // Mock basic stuffs
                config = mock(Config.class);
                Connection = mock(Connection.class);
                rabbitMQProducer = mock(RabbitMQProducer.class); // Imp
    
    
                jasperServerClient = mock(JasperServerClient.class);
    
                rmqConfig = RmqConfig.builder()
                        .host("localhost")
                        .port(5672)
                        .userName("guest")
                        .password("guest")
                        .queueName("somequeue_name")
                        .prefetch(1)
                        .build();
                final String randomMessage = "This is a waste message";
                Message mockMsg = Message.forSending(randomMessage.getBytes(), null, rmqConfig.getQueueName(), rmqConfig.getQueueName(), "text/plain", "UTF-8", true); // prepare a mock message
    
    
                // Prepare service configs
                ConnectionConfig connectionConfig = RmqConfigUtil.getConfig(rmqConfig);
                ProducerConfig producerConfig = new ProducerConfigBuilder()
                        .exchange(rmqConfig.getQueueName())
                        .contentType("text/pain")
                        .contentEncoding("UTF-8")
                        .connection(connectionConfig).build();
                rabbitMQProducer.open(croducerConfig.asMap());
    
                // build the major stuff where the code resides
                someClassObject =  SomeClass.builder()
                        .phoenixConnection(phoenixConnection)
                        .userExchangeName(rmqConfig.getQueueName())
                        .userRabbitMQProducer(rabbitMQProducer)
                        .ftpConfig(config.getFtpConfig())
                        .jasperServerClient(jasperServerClient)
                        .objectMapper(new ObjectMapper())
                        .build();
    
                MockitoAnnotations.initMocks(this);
            }
    
    
            @Test
            public void testNotificationPub() throws Exception {
    
                // Prepare expected Values
                targetNotificationMessage = <<some message>>
    
                // Reflection -  my target functions were private
                Class cls = Class.forName("com.some.path.to.class");
                Object[] objForGetMessage = {<<stuffs>>, <<stuffs>>};
    
                Method getNotificationMessage = cls.getDeclaredMethod("private_fn_1", <<some class>>.class, <<some class>>.class);
                Method pubNotification = cls.getDeclaredMethod("private_fn_2", <<some class>>.class, RabbitMQProducer.class, String.class);
    
                getNotificationMessage.setAccessible(true);
                pubNotification.setAccessible(true);
    
                // Test Case #1
                final <<some class>> notificationMessage = (<<some class>>)getNotificationMessage.invoke(someClassObject, objForGetMessage);
                assertEquals(notificationMessage.getMessage(), targetNotificationMessage);
    
                // Test Case #2 -  this does RMQ call
                Object[] objPubMessage = {notificationMessage, rabbitMQProducer, rmqConfig.getQueueName()};
                final Object publishNotification = pubNotification.invoke(someClassObject, objPubMessage);
                assertEquals(publishNotificationResp, publishNotification); //viola
    
    
                //Important, since RabbitMQProducer is mocked, we need to checkup if function call is made to "send" function which send data to RMQ
                verify(rabbitMQProducer,times(1)).send(any());
    
            }
    
    
            @Test
            public void testMockCreation(){
                assertNotNull(rmqConfig);
                assertNotNull(config);
            }
    
    0 讨论(0)
  • 2021-02-07 20:15

    I know, it is an old question, still as there is no answer so far. What helped me a lot at the same question, is the following blog post: https://tamasgyorfi.net/2016/04/21/writing-integration-tests-for-rabbitmq-based-components/. It uses Apache QPID (not ActiveMQ as suggested in the OP) and it has support for AMQP 0.9.1.

    0 讨论(0)
  • 2021-02-07 20:17

    As I understand it, there are two things trying to be tested in the question:

    • TLS configuration to connect to RabbitMQ
    • basicPublish / basicConsume (what's called delivery) behavior regarding interactions with the rest of the application

    For the first one, as TLS itself is being tested, only connecting to a real instance of RabbitMQ with correct truststore configured will prove that configuration is working

    For the second one however, for tests demonstrating features of the app (with tools like Cucumber for readability), you may try a library i'm working on: rabbitmq-mock (and that's why I'm digging up an old post)

    Just include it as dependency:

    <dependency>
        <groupId>com.github.fridujo</groupId>
        <artifactId>rabbitmq-mock</artifactId>
        <version>1.0.14</version>
        <scope>test</scope>
    </dependency>
    

    And replace new ConnectionFactory() by new MockConnectionFactory() in your unit test.

    Samples are available in the project: https://github.com/fridujo/rabbitmq-mock/blob/master/src/test/java/com/github/fridujo/rabbitmq/mock/IntegrationTest.java

    0 讨论(0)
提交回复
热议问题