Test Driven Development with Alfresco - Part 3 Test Doubles

So far in this series I have given an overview of Test Driven Development and briefly described Inversion of Control.  Proper unit testing requires testing a unit in isolation of its dependencies.  The only thing you care about in relation to a unit's dependencies is how the unit interacts with those dependencies not so much what those dependencies do.  Inversion of Control (IoC) allows us to separate the creation of dependencies from the unit itself but we still need to inject something into our units that we can use for each dependencies.  This is where test doubles come in.  A test double takes the place of an actual dependency.

Types of Test Doubles

There are a lot of different opinions on what test doubles are but the most commonly accepted standard would be from Gerard Meszaros book xUnit Test Patterns: Refactoring Test Code (Addison-Wesley).  These are:
  • Dummy
    • Doesn't do anything and returns null, zero, or the return types nearest equivalent.  Essentially a dummy does nothing and returns nothing.  Dummies are most useful when we don't care how or if there is an interaction with the dummy but it is needed for something.  Perhaps it gets sent into a method of another dependency and we need to check for that.
  • Stub
    • Provides input to the unit being tested.  A stub is a dummy that returns something.  Generally the something is known to the test so the test can use it appropriately to control what is being tested.
  • Spy
    • Provides feedback to the test indicating if an expected method is called.  A spy is a stub that remembers something about how it was called.  You can use a spy to ensure a dependency is called correctly.
  • Mock
    • A mock is a spy that knows how the code was expected to be called.  A mock will have a method that verifies if the expected behavior was called correctly.
  • Fake
    • A fake implementation of the interface.  A fake appears to do real work.  I personally haven't found fakes to be necessary.  If my code is clean to begin with the other test doubles will be cleaner and easier to work with.

Mocking Frameworks

Test doubles can be created manually and to be honest I am on the fence on whether or not that makes more sense.  Robert Martin (Uncle Bob) whom I consider a mentor (through books and videos) makes some excellent points on why manual test doubles are better than using frameworks.  I don't know if I agree with him on that yet and in the meantime I am going to go with what I know and that is mocking frameworks.

Mocking frameworks provide functionality to create test doubles with minimal amount of code.  Not that I want to go into this too much but the problem with the mocking frameworks is they generally require ugly code that is harder to read, which is why Uncle Bob doesn't like them by the way :).

Anyway back to mocking frameworks...

There are a number of mocking frameworks in Java and they are pretty similar.  I prefer Mockito and am going to tailor the rest of this post to that framework.

Mockito

Mockito provides what it refers to as mocks.  Mocks are sort of a hybrid between dummies, spies, and mocks (as described above) with a little bit of fake mixed in.  Mockito mock objects aren't true mocks as they don't actually know how the code was expected to be called, rather they are more or less spies.  Unless you go out of your way to tell Mockito that a given method or property does something or returns a value it does nothing and returns nothing; in this regard the mocks are dummies.  You also have the capability to control how the mock behaves when it is called in certain ways; in this regard they act like fakes.

I am going to review a few of the basics in Mockito but since their documentation is good I am not going to go into much detail.

Creating Mock Objects

There are two ways to create mocks using Mockito.  The first is for on the fly mocks:

1
MyInterface interface = Mockito.Mock(MyInterface.class);

This is useful when you won't be using the mocks more than once and you aren't using generics.  The other way is to use annotations as follows:

1
2
3
4
5
6
7
@Mock
private MyInterface interface;

@Before
public void setup() {
   MockitoAnnotations.initMocks(this);
}

There are two parts that are required here.  The first is the Mock annotation on the variable to be mocked and the second is the call to initMocks to actually initialize the mocks.  This approach ends up being a lot less code and is simpler.  The down side is your mocks are shared across your tests which more often than not ends up not being a problem.  I generally use the second approach unless I explicitly want a mock only available for a given test.  The two approaches can be used in conjunction with each other.

Using Mocks

There are two ways in which a mock can be "used":
  1. To perform work (including returning a value).
  2. To verify that something was called with the expected data.

Perform Work

Be default a mock in Mockito is a dummy.  It does nothing and returns nothing (null or zero).  You can however override this default behavior.  For example suppose you have an Alfresco Service Registry injected into your code and you need to get a node service from it:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
@Mock
private ServiceRegistry serviceRegistry;
@Mock
private NodeService nodeService;

@Before
public void setup() {
   MockitoAnnotations.initMocks(this);

   Mockito.when(serviceRegistry.getNodeService()).thenReturn(nodeService);
}

I recommend using a static import for the when method and replacing Mockito.when with just when.  The when method takes a call on a mock object as a parameter and returns an ongoing stubbing (or simply put returns an object you can indicate what you want to do with).  You can then call the thenReturn method to indicate what is returned.  In this case we are returning our mocked node service whenever we call the getNodeService method of the service registry.

Verify Behaviour

Sometimes you don't care what is returned you only want to know that a method was called.  This is where verify comes into play.  Let's say for example you want to know that a specific aspect was removed:

1
Mockito.verify(nodeService).removeAspect(someNode, MY_ASPECT_QNAME);

Again I recommend using a static import for the verify method.  The verify method takes a mock object and returns a value of that type.  You then specify the parameters that you expected it to be called with.  Sometimes you don't care about some or all of the parameters.  I know this example is a bit contrived but maybe you only care that some aspect was removed so in that case it would look the following:


1
2
verify(nodeService).removeAspect(Mathers.eq(someNode), 
                                 Matchers.any(QName.class));

Again I recommend using a static import for the any and eq methods.  The Matchers class has a number of static methods for validating parameters.  If you specify any of the parameters with a matcher you must specify all.  This is just a rule of using Mockito.  The eq matcher just determines if the value equals the value you have specified, via the equals method with null checks.  The any just makes sure that the parameter is of the type specified.

Another thing to note is that there is nothing wrong with using a mock to both perform work and verify behavior.  Quite often I will start with just verifying behavior but later need it to do real work.  I am not going to go into that right now just keep in mind that there is nothing wrong with that.  In my next post I am sure to run into a situation where that happens.

Conclusion

That about covers test doubles at a high level.  There is more information on the web about the topic and I highly recommend Uncle Bob's video on the topic as well as Gerard's book.

Also that about covers the baseline topics so next time is part 4 where we will actually do Test Driven Development with Alfresco!!! Until then, keep coding!

Comments

Popular posts from this blog

Bootstrapping Rules to Existing Folders in Alfresco

Test Driven Development with Alfresco - Part 1 Introduction to TDD