Friday, June 18, 2010

Mocking Frameworks – Mockito

In order to do any kind of useful testing, you always have to make the odd Simulator or Mock object so that you don’t have to worry about the dependencies that are needed by the particular component you are trying to test.  As long as you take the time to build your code using best practices, you should be able to put your mock object in place during the test without having to change your code for deployment.  I typically use Factory classes to help me do this, but there are other patterns that you can use just as effectively.  A good rule of thumb is to always code to the interface and avoid using the ‘new’ keyword for your implementations in classes that you need to test.  A simple way to do this might be:

public final Class SomeThing {
  private SomeThing() {}
  private static ISomeThing instance;
  public static ISomeThing getInstance() {
    if ( instance == null ) {
      instance = new SpecificSomeThing();
    }
    return instance;
  }
  public static void setInstance(ISomeThing someThing) {
    instance = something;
  }
}

When I want to use an instance of ISomeThing, I just call:

final ISomeThing someThing = SomeThing.getInstance();

Assuming that you are comfortable with this idea, you’ve now decoupled your dependency ISomeThing from your code and now you can test whatever calls an ISomeThing without having to manipulate the world that your dependant ISomeThing lives in…you can simply Mock it.


Lets assume that your ISomeThing looks like this:

public interface ISomeThing {
  boolean isTheAnswer(int answer);
}

To create a Mock implementation of ISomeThing, you could create something like this:

public class MockSomeThing implements ISomeThing {
   public boolean isTheAnswer(int answer) {
      return answer == 64;
   }
}

So now before you test, you just make your factory return your Mock object instead of the regular implementation of the object.

SomeThing.setInstance(new MockSomeThing());

What will happen is that when your class uses the ISomeThing instance declared in the code by the factory class, it will return true if it is supplied with the input of 64, otherwise it will return false…(hitch-hiker metaphor intended)

public void testMock() {
  SomeThing.setInstance(new MockSomeThing());
  final ISomeThing s = SomeThing.getInstance();
  
  assertTrue(s.isTheAnswer(64));
  assertFalse(s.isTheAnswer(99));
}

The only issue is that now I have a really useless class in my code base that tells me that 64 is the answer.  If I use a mocking framework  I could do this without actually creating a mock implementation:

import static org.mockito.Mockito.*;
public void testMock(){
  final ISomeThing s = mock(ISomeThing.class);
  when(s.isTheAnswer(64)).thenReturn(true);
  assertTrue(s.isTheAnswer(64));
  assertFalse(s.isTheAnswer(99));
}

This gives me the behavior I need without actually implementing the interface.  Clean and simple.

No comments: