19 March 2012

Mockito is awesome!

Sometimes you need to test the "exceptional" behavior of your application just to make sure that an alternate path of your code, often needed to cope with an exception, perform as expected.

In these cases, writing a unit test is often complicated from the need to mimic some exception on external infrastructure services.

But wait! Mocking frameworks are made just for this... 

Ok let's keep in mind for now. Now imagine having to test the code that handle a specific exception of a jms messaging system.
The exception occurs infrequently so it is vain to hope of catching the case in an integration test, neither you can purposely provoke it.
All that remains is to simulate it on a unit test.

...It does not sound so simple. 

Wrong! With Mockito it's a breeze and with its fluent interface it's also funny!

Let's see how:

How to easily test spring jmstemplate

This is the method to test, a bit ugly, but self explaining:
public boolean send(final MyMessageInterface message) {
  int retryCount=0;
  int maxRetries=3;
  while (true) {
   try {
    jmsTemplate.execute(destination, new MyProducerCallback(message));
    return true;
   } catch (JmsException e) {
    if (++retryCount < maxRetries) {
     try {
      Thread.sleep(1000);
     } catch (InterruptedException e1) {
      // swallowed
     }
    } else if (e.getCause() instanceof some.vendor.CustomJmsException && failoverEnabled) {
     template.execute(fallbackDestination, new MyProducerCallback(message));
     return true;
    } else {
     throw e;
    }
   } 
  }
 }

And this is the test class:

import static org.junit.Assert.fail;
import static org.mockito.Mockito.*;
import javax.jms.BytesMessage;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Queue;
import javax.jms.Session;
import org.junit.Before;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.jms.JmsException;
import org.springframework.jms.UncategorizedJmsException;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.ProducerCallback;
import my.app.MyMessageInterface;
import some.vendor.CustomJmsException;
import some.vendor.CustomMessageProducer;

public class MySenderClassTest {

    MySenderClass testSubject;
    JmsTemplate mockTemplate;
    Session mockSession;
    CustomMessageProducer mockRemoteProducer;
    CustomMessageProducer mockLocalProducer;
    Queue mockQueue;
    Queue mockLocalQueue;
    BytesMessage mockMessage;

    @Before
    @SuppressWarnings("unchecked")
    public void setUp() throws Exception {
        testSubject = new MySenderClass();
        mockTemplate = mock(JmsTemplate.class);
        mockSession = mock(Session.class);
        mockRemoteProducer = mock(CustomMessageProducer.class);
        mockLocalProducer = mock(CustomMessageProducer.class);
        mockQueue = mock(Queue.class);
        mockLocalQueue = mock(Queue.class);
        mockMessage = mock(BytesMessage.class);
        when(mockTemplate.execute((Destination) anyObject(), (ProducerCallback<Void>) anyObject())).thenAnswer(
                new Answer<Void>() {

                    @Override
                    public Void answer(InvocationOnMock invocation) throws Throwable {
                        Object[] args = invocation.getArguments();
                        Destination dest = (Destination) args[0];
                        ProducerCallback<Void> pc = (ProducerCallback<Void>) args[1];
                        return pc.doInJms(mockSession, dest.equals(mockQueue) ? mockRemoteProducer : mockLocalProducer);
                    }
                });

        when(mockSession.createBytesMessage()).thenReturn(mockMessage);
        when(mockQueue.toString()).thenReturn("mocked distributed queue");
        when(mockLocalQueue.toString()).thenReturn("mocked local queue");
        testSubject.setDestination(mockQueue);
        testSubject.setFallbackDestination(mockLocalQueue);
        testSubject.setFailoverEnabled(true);
        testSubject.setJMSTemplate(mockTemplate);
    }

    @Test
    public void sendSuccessTest() throws Exception {
        testSubject.send(new MyTestMessage("my-valid-key"));
    }

    @Test
    public final void sendFailAfterThirdRetryTest() throws JMSException {
        doThrow(new UncategorizedJmsException(new CustomJmsException("mock exception"))).when(mockRemoteProducer).send((BytesMessage) anyObject());
        testSubject.send(new MyTestMessage("my-invalid-key"));
        verify(mockRemoteProducer, times(3)).send((Message) anyObject());
        verify(mockLocalProducer, times(1)).send((Message) anyObject());
    }

    public static final class MyTestMessage implements MyMessageInterface {
       //...
    }
}

Here you can find a very good presentation on Mockito and testing approaches by Per Lundholm.

Update 18/05/2012: Someone has rightly noted that the retries in the test subject, could be better addressed through a separate aspect.
Actually resorting to an aspect would help to clean up the code by separating the responsibility for sending to those of exception and subsequent retries handling,

In the past, I've used too AOP with mixed results and feelings.

While completely agreeing with the observation I prefer to keep as is the example code, though ugly and messed up, for lack of time and laziness mainly :), and to not complicate too much the example by introducing new topics.
As always, suggestions are welcome.

28 September 2011

CQRS and Design by Contract

Getting closer to CQRS and its valuable java implementation Axon Framework, I found that it goes very well with one of my favorites concepts in computer programming: Design by Contract  (something that I really miss in my daily work on java - but that's another story...)

The reason of my appreciation is that I see in Design by Contract the application of a more general principle, as part of the Domain Driven Design, that leads to "Make implicit concepts explicit".

Thinking about the causes of this affinity, the relationship between CQRS and DbC becomes immediately clear: CQRS incorporates and expands the scope of CQS from the design level, in which it was confined at the beginning, to an architectural point of view.
But CQS and DbC were both conceived by the same father, Bertrand Meyer...

I don't want to go through well known concepts that were explained by others better than I could ever do. I just want to highlight  this small positive fact:
Separation of command handling from event handling gives, among the others benefits, a clear distinction between where to perform the contextual validation of the command - that is necessary to ensure the respect of client obligations (by applying preconditions) - and where to enforce the validation of your business rules  - that is necessary to ensure the respect of server obligations (by applying postcondtions and invariants)

A simple demonstration
Suppose that you have a Ranking class which is responsible for the ranking list of a game's participants.

The Ranking class in this example acts as an aggregate root, that, by extending Axon Framework AbstractAnnotatedAggregateRoot class, obtains for free event sourcing persistence and event raising and handling capabilities.

Please note that the same capabilites are offered by Axon to child entities of the aggregate, but in this case the class to extend is the AbstractAnnotatedEntity class.
In such cases you should take a closer look at paragraph named Complex Aggregate structures in the documentation.


Now let's imagine that you want to add a player in a particular position of this ranking.
You would create some RankPlayerCommand to dispatch command values and a specialized Command Handler that handles such a command.

I let these tasks to your own fantasy. Now let's focus on the rankPlayer method on the Ranking class that is invoked by the command handler:

   /**
     *  Add a player at the specified rank
     * 
     *  Precondition 1: Cannot assign the same rank to more than one player.
     *  Precondition 2: Each player cannot get more than one position.
     *
     * @param rank 
     * @param player 
     */
    public void rankPlayer(int rank, Player player) {
        boolean isFreeRank = !players.containsKey(rank);
        boolean isNew = !players.containsValue(player);
        Contract.REQUIRE.isTrue(isFreeRank, "Cannot assign the same rank to more than one player.", "The rank [{}] is already assigned.", rank);
        Contract.REQUIRE.isTrue(isNew, "Each player cannot get more than one position.", "The player [{}] is already in this ranking.", player);
        apply(new PlayerRankedEvent(rank, player));
    }

As you can see in the example above, the main responsibility of the rankPlayer method is, as said before, to ensure the respect of client obligations specified in the contract.
These obligations are enforced by applying preconditions that, for clarity's sake, are reported in the javadoc. Then the method is free to raise the appropriate event for its case.
The applied event is handled locally by the same entity, in this case our Ranking class, through a method annotated with @EventHandler in the following way:

 
   /**
     * Postcondition 1: Players list must contains the new player.
     * Postcondition 2: Players list size must grows by one.
     * 
     * @param ev @see RankingPlayerInsertEvent
     */
    @EventHandler
    void onPlayerRanked(PlayerRankedEvent ev) {
        int initialSize = players.size();
        players.put(ev.getRank(), ev.getPlayer());
        boolean isContained = players.containsValue(ev.getPlayer()) && players.get(ev.getRank()).equals(ev.getPlayer());
        final boolean isSizeEncreased = players.size() == ++initialSize;
        Contract.ENSURE.isTrue(isContained, "Players list must contains the new player.", "Missing element");
        Contract.ENSURE.isTrue(isSizeEncreased, "Players list size must grows by one.", 
                "Unexpected size! Actual size: [{}] expected: [{}]", players.size(), initialSize);
        testInvariants();
    }

    /**
     * Invariant 1: Ranking players must be lesser or equals than Game participants 
     */
    private void testInvariants() {
        int playersSize = players.size();
        int participantsSize = getGameParticipantsSize();
        boolean isPlayersSizeValid = (playersSize <= participantsSize); 
        Contract.INVARIANT.isTrue(isPlayersSizeValid, "Ranking players must be lesser or equals than Game participants", 
                "Game participants are [{}] lesser than the number of players [{}] in this ranking", participantsSize, playersSize);
    }

In the event handler, finally, you can apply the appropriate state changing logic but, before exiting, you need to ensure that your implementation respects the obligations towards the client which are stated in the contract.

Again, these obligations are exposed explicitly in the javadoc and enforced by the application of postconditions.

Moreover, due to the state changes applied, the event handler must also ensure the respect of class invariants, that, being class scoped, are verified through an external method.

The Test
It's time to stress our business logic to verify if the contract that applies to our RankPlayerCommand behaves as expected. Let's make some tests:

Axon framework includes promising testing features that lets build up easily test scenarios which took the following form: given - when - then.
This type of scenario can be used to map user stories that usually are shaped in this way: - As a <role>, I want <goal/desire> so that <benefit> - and it turn out to be useful to test the behavior of the application and to derive acceptance tests.

First we want to test the application behavior in the flow of the regular use case:

public class RankingCommandHandlerTest {
    
    private FixtureConfiguration fixture;
 
    private Player player1 = new Player("P1", "Player1");

    ...
    
    @Test
    public void testAddPlayer() {
        RankPlayerCommand c2 = new RankPlayerCommand(fixture.getAggregateIdentifier().asString(), "P1", "Player1", 1);
        PlayerRankedEvent ev = new PlayerRankedEvent(1, player1);
        fixture.given(new RankingCreatedEvent("MyGame")).when(c2).expectEvents(ev);
    }

Then we test the behavior in misuse cases that have been covered by the preconditions:

   
   ...

   private Player player2 = new Player("P2", "Player2");

   ...

   @Test()
    public void testFailWhenAddSameRank() {
        RankPlayerCommand c2 = new RankPlayerCommand(fixture.getAggregateIdentifier().asString(), "P1", "Player1", 1);
        PlayerRankedEvent ev = new PlayerRankedEvent(1, player2);
        fixture.given(new RankingCreatedEvent("MyGame"), ev).when(c2).expectException(PreConditionException.class);
    }
    
    @Test()
    public void testFailWhenAddSamePlayer() {
        RankPlayerCommand c2 = new RankPlayerCommand(fixture.getAggregateIdentifier().asString(), "P1", "Player1", 1);
        PlayerRankedEvent ev = new PlayerRankedEvent(2, player1);
        fixture.given(new RankingCreatedEvent("MyGame"), ev).when(c2).expectException(PreConditionException.class);
    }

In both cases we expect an exception to be thrown: