Type of Mocks
A long time ago (year 2000), the mock objects were invented. It is now one of the most important parts of unit testing.
For those you don’t know, the idea of a mock object is to simulate a dependency to easily test a class. Quick example.
I have a class Pricer
.
Being a nice human being, I want to test my calculations but I don’t want to use a real PriceFeed
. The real implementation
has to an actual MQSeries queue that received prices from Reuters. It’s not something you want to do during your unit tests
(if at all).
So you will instead do a mock object, an object that will behave as you see fit for your test but that isn’t a real PriceFeed
. It just
mimics it.
Not so long ago, Uncle Bob did a blog post about mock objects. He classifies them into five different types or levels. Levels because each type is wiser than the previous one. He calls them “Test Doubles”.
I’ve decided to show you how to code them. Using EasyMock (of course), Mockito and by hand.
Type of mocks
From the most basic to the most advanced type.
Dummy
A class that you pass into something when you don’t care how it’s used. e.g. As part of a test, when you must pass an argument, but you know the argument will never be used.
In this EasyMock world, it is called a nice mock (Authorized mock = niceMock(Authorized.class)
).
In the Mockito world, it’s just a mock (Authorized mock = mock(Authorized.class)
).
In general, if a dummy is used, you will want it to throw an exception to tell you something is
wrong. So, with Mockito, you will in general get a NullPointerException
(or not) if you do something like
if(mock.authorize(user, password)) // NPE
With EasyMock, you will generally prefer to use a normal mock (Authorized mock = mock(Authorized.class)
) that
will make sure nothing unintended is called.
if(mock.authorize(user, password)) // AssertionError: Unexpected method call
Stub
A class that returns a valid answer but always the same one.
In the EasyMock language, this is any mock with an expectation recorded (expect(mock.authorize(anyString(), anyString()).andStubReturn(true)
).
In the Mockito language, this is a mock with behavior set on a method (when(mock.authorize(any(), any()).thenReturn(true)
.
Spy
You use a spy when you want to be sure that the authorize()
method is called by the system.
In EasyMock, it means you are not stubbing anymore. You want to record a precise call (expect(mock.authorize(anyString(), anyString()).andReturn(true)
)
and then verify that the call actually occurred (verify(mock)
).
In Mockito, you still stub the call and then verify the call occurred (verify(authorizer).authorize(any(), any())
). Note that Mockito has its own
concept of a spy, which is different. A Mockito spy is a shell over an actual class that allows to verify calls to them. It is indeed useful
but it isn’t a mock. So don’t get lost in the semantic.
True Mock
A true mock is a mock that knows how to verify itself. In fact, EasyMock and Mockito mocks are always true mocks. So their implementations of a true mock is the same as for the spy.
Fake
A Fake has business behavior. You can drive a fake to behave in different ways by giving it different data. They are usually used for integration testing to simulate other parts of your system.
I rarely use a mocking framework for them. It tends to make the code more complicated than coding by hand. Still, a mocking framework can be used.
Conclusion
When jumping from one flavor to another, you should make sure you really need to. Because the more complicated your mocking is, the more coupling you will have with the actual implementation. It makes the test more fragile. But you still need to make sure everything is working as expected!
Testing advice
Modify to test
If your code isn’t easy to test, modify your code. Do whatever is needed. You will end up with a better design anyway. A test should not be complicated. If it needs to, something is wrong.
Provide a testing framework
If you build something, you should provide a nice framework to test it. Spring has spring-test. You are responsible for making what you do testable, mockable, etc.
Use as less mocks as possible
Usually, unit tests should use at worst 3 mocks. It you have more, you probably should split your code in smaller parts. A lot of mocks makes the code unreadable.
Explain and document your tests
Tests are harder to understand than actual production code. When someone reads test code, he should understand the purpose. So use a nice test name to explain what you wanted to do. Use javadoc. Use line comments to explain the flow.
Refactor them
I’m refactoring my tests a lot. A lot. Nice methods preventing copy & paste. Testing frameworks. Fixtures. Base test classes. Everything to make it as pretty as my production code.