Mockito - Integration testing made easier
By Carey Morris, OCI Senior Software Engineer
September 2010
Introduction
It could be argued that full testing of applications is just as important as the application itself. So any tool that makes testing easier and more natural is highly beneficial. Previously, there have been many Java News Briefs (here and here) that address testing functionality in isolation without requiring expensive resource setup/execution/teardown or when resources are not available. In these examples, Mock objects play the role of providing a "mock" representation of these resources. Dependency injection and mock objects go hand in hand. Mock objects allow us to mock out these dependencies. Using standard dependency injection (regardless of whether you are using Java EE, Spring or Guice), you can then inject those mocked objects into your component and verify interactions.
However, coding mock objects by hand is quite a lot of work. The Mockito framework assists this process by using mock objects in a natural easy-to-use way without creating "noise" that interferes with effective testing.
In this JNB, I will introduce Mockito and explain how it can be used effectively. I'll also discuss some helpful tips on using Mockito and some limitations.
Benefits of Mockito
While there are other mocking frameworks around (EasyMock, jMock, etc.), Mockito provides a test framework with the following advantages:
- Simplicity: Interactions are method calls without requiring a sophisticated mocking language.
- Slim Logical API: The API is minimized so that anyone can use it efficiently and produce good clean code. If a class is difficult to test the it should be refactored.
- Focus on Testing: Focus test methods on specific behavior/interaction and minimizes distractions like expecting/recording irrelevant interactions.
- Clean Stack Traces: Internal library details are hidden in code that produces testing errors. Error stacktraces take you directly to the source of the problem.
- Under active development
Mockito Setup
If you are using maven, ensure the Mockito jar is included in the pom as follows. Otherwise, add the latest mockito-all-x.x.jar
to your classpath.
- <dependency>
- <groupid>org.mockito</groupid>
- <artifactid>mockito-all</artifactid>
- <version>1.8.5</version>
- <scope>test</scope>
- </dependency>
An Example Class to test
Our class to test will be an implementation of a filter that counts characters and can be part of a chain of filters. The next filter in the chain is injected into class. An interface defines the filter:
- package com.ociweb.jnb;
-
- public interface Filter {
- int send(String string);
- String read();
- void resetInput();
- }
And an implementation of the counter filter. The CounterFilter
maintains a count of received and sent characters. The nextfilter field points to the next filter in the chain which could perform any type of filtering task. Spring handles the dependency injection via the @Autowire
or @Component
annotations.
- public class CounterFilter implements Filter {
- Filter nextFilter;
-
- long charactersSent = 0;
- long charactersReceived = 0;
-
- public CounterFilter(Filter nextFilter) {
- this.nextFilter = nextFilter;
- }
-
- public long getCharactersSent() {
- return charactersSent;
- }
-
- public long getCharactersReceived() {
- return charactersReceived;
- }
-
- public void resetCounters() {
- charactersSent = 0;
- charactersReceived = 0;
- }
-
- @Override
- public int send(String output) {
- charactersSent += output.length();
- // send output to injected
- return serialCommunicator.send(output);
- }
-
- @Override
- public String read() {
- String input = serialCommunicator.read();
- charactersReceived += input.length();
- return input;
- }
-
- @Override
- public void resetInput() {
- charactersSent = 0;
- charactersReceived = 0;
- }
- }
A first test case
First we import the needed Mockito classes statically for simplicity.
- import static org.mockito.Mockito.*;
-
- @Test
- public void testVerifyBasicInteractions() {
- CounterFilter filter = mock(CounterFilter.class);
-
- filter.send("c");
- String string = filter.read();
- verify(filter).send("c"); // verify behavior happened once
- verify(filter, times(1)).read(); // again, verify behavior happened once
- }
Here we are directly mocking our class under test for basic verification that methods were called. This case is not very useful but it does demonstrate the ease of which mock objects are created and verified.
The mock
method creates a mock object of given class or interface.
The verify
method verifies certain behavior happened at least once / exact number of times / never. In this case, we verify that the send()
and the receive()
methods are called exactly 1 time. We also verify that the send method was called with the string "c". Note that leaving off the second parameter to the verify method defaults to "exactly once" or times(1).
Basic Stubbing
In this example we create a mock for the injected class (Filter
). The when
clause is used to define the behavior of the collaborating object (mockFilter
).
- @Test
- public void testStubMethodCalls() {
- Filter mockFilter = mock(Filter.class);
- CounterFilter counterFilter = new CounterFilter(mockFilter);
-
- // define behavior of collaborating class
- when(mockFilter.send(anyString())).thenReturn(1);
-
- // interact with the class under test
- String aString = "abc";
- assertEquals(1, counterFilter.send(aString));
- assertEquals(3, counterFilter.getCharactersSent());
-
- // verify some class functionality.
- verify(mockFilter, times(1)).send(aString);
- }
Here we have a counterFilter
object containing a mockFilter
that is the collaborating object. First we define the behavior of the collaborating mock object to return 1 when any string is sent. The syntax is simply "When the x method is called then return y". anyString()
defines an argument matcher that matches any input string.
Then we interact with the class under test (counterFilter
) and assert that the return values are as expected.
Lastly, we verify that the mockFilter
was called the expected number of times and passed the original string ("abc").
Argument Matchers
Mockito verifies argument values by using an equals()
method. When extra flexibility is required then you might use argument matchers.
Here is a subset of the argument matchers.
any()
- matches any object or nullanyInt(), anyString(), etc.
- matches primitives or their wrapperseq(int value), eq(String value), etc.
- argument matches the given valuenotNull(
) - not a null argumentsame(T value)
- object argument is the same as the given valueanyCollection(), anyCollectionOf(java.lang.Class)
- matches any collection (generic friendly)matches(String regexp)
- matches a given regular expression
Click here to see a full list of built in argument matchers.
You can also create custom matches using the argThat
matcher as in this example.
- class IsListOfTwoElements extends ArgumentMatcher<List> {
- public boolean matches(Object list) {
- return ((List) list).size() == 2;
- }
- }
- List mock = mock(List.class);
- when(mock.addAll(argThat(new IsListOfTwoElements()))).thenReturn(true);
- mock.addAll(Arrays.asList("one", "two"));
- verify(mock).addAll(argThat(new IsListOfTwoElements()));
Exception Handling
In this example we define behavior for mocking exception handling. Notice the use of the matcher argument matcher. For brevity, I will dispense with the repetitive mock object creation.
when(mockFilter.send(matches("\\s"))).thenThrow(new IllegalArgumentException()); // matches a whitespace character
Stubbing voids requires a different approach from when() because the compiler does not like void methods inside brackets. Thus, if we want the read method to throw an exception we use doThrow().
- doThrow(new IllegalArgumentException()).when(mockFilter).read();
-
- try {
- counterFilter.send(" ");
- fail("Expected IllegalArgumentException for send method");
- } catch (IllegalArgumentException e) {
- }
- try {
- counterFilter.read();
- fail("Expected IllegalArgumentException for read method");
- } catch (IllegalArgumentException e) {
- }
- assertEquals(1, counterFilter.getCharactersSent());
- verify(mockFilter, times(1)).send(anyString());
Consecutive stubbing and eq Matcher
In this test, consecutive stubbing is used to return different values upon multiple calls to a method.
- when(mockFilter.read()).thenReturn("abc", "def"); // consecutive stubbing
- assertEquals("abc", counterFilter.read());
- assertEquals("def", counterFilter.read());
- verify(mockFilter, times(2)).read();
-
- // demonstrates the eq match on a given object
- String myString = "myString";
- when(mockFilter.send(eq(myString))).thenReturn(1000);
- assertEquals(1000, counterFilter.send(myString));
- verify(mockFilter, atLeast(1)).send(myString);
We also make use of the eq
matcher that matches a given string.
Shorthand for creating Mocks
The @Mock
annotation can be used to define a mock object. The advantages are:
- Minimizes repetitive mock creation code.
- Makes the test class more readable.
- Makes the verification error easier to read because the field name is used to identify the mock.
- public class CounterFilterTest {
-
- @Mock
- private Filter annotatedMockFilter;
However, for this to work then this needs to be in the base class or a test runner.
MockitoAnnotations.initMocks(testClass)
Our test class could extend SampleBaseTestCase
which contains:
- package com.ociweb.jnb.test;
-
- import org.junit.Before;
- import org.mockito.MockitoAnnotations;
-
- public class SampleBaseTestCase {
-
- @Before public void initMocks() {
- MockitoAnnotations.initMocks(this);
- }
- }
Miscellaneous
Other interactions include:
- Verifying interactions never occurred on a mock
- //verify that method was never called
- verify(mockOne, never()).add("two");
-
- //verify that other mocks were not interacted
- verifyZeroInteractions(mockTwo, mockThree);
- Finding redundant invocations
verifyNoMoreInteractions(mockedObj),
- Stubbing consecutive calls
when(mock.someMethod("some arg")).thenReturn("one", "two", "three");
Tips
- Mockito's javadoc contains full documentation. It's easy to use your IDE to look at the javadoc for a desired Mockito method to see full documentation on it's functionality.
- The Mockito API method reset() allows the mock object to be reset. However, this is probably an indication of a test that is trying to do to much. Consider writing simple, small tests focused on single behavior.
- If you are using argument matchers, all arguments have to be provided by matchers.
- verify(mock).someMethod(anyInt(), anyString(), eq("third argument"));
- // Above is correct - eq() is also an argument matcher
-
- verify(mock).someMethod(anyInt(), anyString(), "third argument");
- // Above is incorrect - exception will be thrown because third argument is
- // given without an argument matcher.
Limitations
- Requires Java 1.5 or above
- Can not mock
- final classes
- static methods
- final methods- their real behavior is executed without any exception
equals()
orhashCode()
- Mockito defines and depends upon a specific implementation of these methods. Redefining them might break Mockito.
Summary
Mockito is an excellent framework for verifying component behavior especially when there are collaborating objects that require mocking. Mockito uses a natural language to define behavior of mocked objects and to verify the expected behavior making tests simple and readable.
References
- [1] The Mockito web site
http://mockito.org. - [2] The Mockito API:
http://mockito.googlecode.com/svn/tags/latest/javadoc/org/mockito/Mockito.html. - [3] A comparison of Mockito to EasyMock:
http://code.google.com/p/mockito/wiki/MockitoVSEasyMock. - [4] Mockito: Java Unit Testing with Mock Objects:
http://www.developer.com/java/other/article.php/3882311/Mockito-Java-Unit-Testing-with-Mock-Objects.htm. - [5] SETT Article - Mock Objects and Distributed Testing by Brian Gilstrap:
https://objectcomputing.com/resources/publications/sett/august-2005-mock-objects-and-distributed-testing-by-brian-gilstrap-principal-software-engineer. - [6] SETT Article - Designing Testability with Mock Objects by Mario Aquino:
https://objectcomputing.com/resources/publications/sett/june-2003-designing-testability-with-mock-objects. - [7] Easymock:
http://easymock.org.