Pragmatic Programmer Issues

Spring Template Objects Testing

Comments: 2

My friend asked me, how we should test this piece of code

public void fire(final NotificationMessage message) {
  jmsTemplate.send(new MessageCreator() {
    @Override
    public Message createMessage(Session session) throws JMSException {
      return session.createObjectMessage(message);
    }
  });
}

Mock, stubs, arguments matchers are not successful here. Of course we can mock jmsTemplate, verify if send method was executed, but this way we only test if springframework works properly. Should we leave this to integration test?

Of course not, and our business part is: session.createObjectMessage(message). We have to change our code. First at all we provide second method.

public void fire(final NotificationMessage message) {
  this.fire(message, getMessageCreator(message));
}
public|protected| void fire(final NotificationMessage message, MessageCreator mc) {
  jmsTemplate.send(mc);
}

This two methods are easily testable by using mocks and verifying object interactions. We can decide about method modifier:

  • public – if we want second function to be available in our API.
  • protected – for future subclass usage.
  • package public – for use in package.
  • or even private

Finally we have decide about getMessageCreator(message).

  1. Provide Factory Method for it: MessageCrator getMessageCreator(NotificationMessage message);
    MessageCreator getMessageCreator(final NotificationMessage message) {
      return new MessageCreator() {
        @Override
        public Message createMessage(Session session) throws JMSException {
          return session.createObjectMessage(message);
        }
      };
    }
    
  2. Create Class which implements MessageCreator interface
    public class NotificationMessageCreator implements MessageCreator {
        private final NotificationMessage message;
    
        public NotificationMessageCreator(NotificationMessage message) {
            this.message = message;
        }
        @Override
        public Message createMessage(Session session) throws JMSException {
            return session.createObjectMessage(message);
        }
    }
    

I think both approaches are ok, so choose better one for you.

Of course you may argue that you don’t need unit test, you will have integration test for that part of the code. Unfortunately integration tests are slow and from time to time they fail, so for simple check I prefer unit test.

Summary

We use a lot of Spring Template Object helpers, and most of the time we are tempted to create anonymous class in place. This way we make our code hard to unit test. Consider this approach to make your code easier to test and maintain. What do you think about that?


Comments

miluchmiluch

Hi

Any test doubles: stubs/mocks fall shortly when your tests need to check against collaboration with objects created within methods by ”
“new”.Usage of anonymous inner classes makes things even worse.
If you do not apply any voodoo like PowerMocks this kind of code is nearly untestable.

In the case you shown above i think i will employ the second approach: you could easily test NotificationMessageCreator class in isolation (to test proper creation of JMS message).
Following this approach you could easily test that jmsTemplate is called with instance of NotificationMessageCreator object as parameter as well.

regards miluch

Marco TedoneMarco Tedone

Inner classes are evil, so I like your approach. Well done Pedro.