skip to Main Content

I am using Redis Server for message broker in my spring boot application.
Is there any simple way to Junit my publish and receive API?

e.g :

Publisher :

public String publish(Object domainObj) {

    template.convertAndSend(topic.getTopic(), domainObj.toString());
    return "Event Published";
}

Receiver :

public class Receiver implements MessageListener {

@Override
public void onMessage(Message message, byte[] bytes) {

    System.out.println("Consumed Message {}" + message);

}

}

I am using JedisConnectionFactory and RedisMessageListenerContainer and RedisTemplate for my implementation

@Configuration
@EnableRedisRepositories
public class RedisConfig {

    @Bean
    public JedisConnectionFactory connectionFactory() {
        RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
        configuration.setHostName("localhost");
        configuration.setPort(6379);
        return new JedisConnectionFactory(configuration);
    }

    @Bean
    public RedisTemplate<String, Object> template() {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory());
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new JdkSerializationRedisSerializer());
        template.setValueSerializer(new JdkSerializationRedisSerializer());
        template.setEnableTransactionSupport(true);
        template.afterPropertiesSet();
        return template;
    }

    @Bean
    public ChannelTopic topic() {
        return new ChannelTopic("common-channel");
    }

    @Bean
    public MessageListenerAdapter messageListenerAdapter() {
        return new MessageListenerAdapter(new Receiver());
    }

    @Bean
    public RedisMessageListenerContainer redisMessageListenerContainer() {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory());
        container.addMessageListener(messageListenerAdapter(), topic());
        return container;
    }

2

Answers


  1. The simplest way to unit test this is to use embedded-redis module. What you do is in BeforeAll you can start embedded Redis and stop the embedded Redis in AfterAll method.

    You can also PostConstruct PreDestroy annotations to accomplish this.

    If you’re looking for Junit5 then you can find the code in my repo here

    See BootstrapRedis annotation and their usage here

    https://github.com/sonus21/rqueue/blob/7ef545c15985ef91ba719f070f7cc80745525047/rqueue-core/src/test/java/com/github/sonus21/rqueue/core/RedisScriptFactoryTest.java#L40

    Login or Signup to reply.
  2. Unit Testing Receiver and Publisher implementation is quite straight.
    JUnit 5 coupled with Mockito extension should do the job.

    For example for testing that :

    public String publish(Object domainObj) {
        template.convertAndSend(topic.getTopic(), domainObj.toString());
        return "Event Published";
    }
    

    I expect that topic and template be fields of the current class.
    These fields could be set by constructor.

    So you could write something that check that convertAndSend() is eventually executed with the correct parameters :

    @Mock 
    RedisTemplate<String, Object> templateMock;
    
    @Test
    void publish(){
       Topic topicFixture = new Topic(...);
       Object domainObjFixture = new FooBar(...);
       Publisher publisher = new Publisher(templateMock, topicFixture);
       //when
       publisher.publish(domainObjFixture);
       // then
       Mockito.verify(templateMock)
              .convertAndSend(topicFixture.getTopic(), domainObjFixture);      
    }
    

    But I don’t think that the unit test of these two classes be enough because it never tests the final things : the JMS processing performed by Redis backend.
    Particularly, the RedisConfig part that you set with specific things as serializers that have important side effects on the processing.
    For my part, I try to always write integration or partial integration tests for Redis backend stuffs to ensure a good no regression harness.

    The java embedded-redis library is good for that. It allows to start a redis server
    on localhost (works on Windows as well as on Linux).
    Starting and stopping the redis server is as simple as :

    RedisServer redisServer = new RedisServer(6379);
    redisServer.start();
    // do some work
    redisServer.stop();
    

    Move the start() in the @BeforeEach and the stop() in the @AfterEach and the server is ready.
    Then it still requires some adjustments to ensure that the redis configuration specified in Spring is well setup during the tests while using your local redis server and not the "real" redis server. Not always simple to set but great when it is done !

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search