Mockito - Integration testing made easier

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 (EasyMockjMock, etc.), Mockito provides a test framework with the following advantages:

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.

  1. <dependency>
  2. <groupid>org.mockito</groupid>
  3. <artifactid>mockito-all</artifactid>
  4. <version>1.8.5</version>
  5. <scope>test</scope>
  6. </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:

  1. package com.ociweb.jnb;
  2.  
  3. public interface Filter {
  4. int send(String string);
  5. String read();
  6. void resetInput();
  7. }

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.

  1. public class CounterFilter implements Filter {
  2. Filter nextFilter;
  3.  
  4. long charactersSent = 0;
  5. long charactersReceived = 0;
  6.  
  7. public CounterFilter(Filter nextFilter) {
  8. this.nextFilter = nextFilter;
  9. }
  10.  
  11. public long getCharactersSent() {
  12. return charactersSent;
  13. }
  14.  
  15. public long getCharactersReceived() {
  16. return charactersReceived;
  17. }
  18.  
  19. public void resetCounters() {
  20. charactersSent = 0;
  21. charactersReceived = 0;
  22. }
  23.  
  24. @Override
  25. public int send(String output) {
  26. charactersSent += output.length();
  27. // send output to injected
  28. return serialCommunicator.send(output);
  29. }
  30.  
  31. @Override
  32. public String read() {
  33. String input = serialCommunicator.read();
  34. charactersReceived += input.length();
  35. return input;
  36. }
  37.  
  38. @Override
  39. public void resetInput() {
  40. charactersSent = 0;
  41. charactersReceived = 0;
  42. }
  43. }

A first test case

First we import the needed Mockito classes statically for simplicity.

  1. import static org.mockito.Mockito.*;
  2.  
  3. @Test
  4. public void testVerifyBasicInteractions() {
  5. CounterFilter filter = mock(CounterFilter.class);
  6.  
  7. filter.send("c");
  8. String string = filter.read();
  9. verify(filter).send("c"); // verify behavior happened once
  10. verify(filter, times(1)).read(); // again, verify behavior happened once
  11. }

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).

  1. @Test
  2. public void testStubMethodCalls() {
  3. Filter mockFilter = mock(Filter.class);
  4. CounterFilter counterFilter = new CounterFilter(mockFilter);
  5.  
  6. // define behavior of collaborating class
  7. when(mockFilter.send(anyString())).thenReturn(1);
  8.  
  9. // interact with the class under test
  10. String aString = "abc";
  11. assertEquals(1, counterFilter.send(aString));
  12. assertEquals(3, counterFilter.getCharactersSent());
  13.  
  14. // verify some class functionality.
  15. verify(mockFilter, times(1)).send(aString);
  16. }

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.

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.

  1. class IsListOfTwoElements extends ArgumentMatcher<List> {
  2. public boolean matches(Object list) {
  3. return ((List) list).size() == 2;
  4. }
  5. }
  6. List mock = mock(List.class);
  7. when(mock.addAll(argThat(new IsListOfTwoElements()))).thenReturn(true);
  8. mock.addAll(Arrays.asList("one", "two"));
  9. 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().

  1. doThrow(new IllegalArgumentException()).when(mockFilter).read();
  2.  
  3. try {
  4. counterFilter.send(" ");
  5. fail("Expected IllegalArgumentException for send method");
  6. } catch (IllegalArgumentException e) {
  7. }
  8. try {
  9. counterFilter.read();
  10. fail("Expected IllegalArgumentException for read method");
  11. } catch (IllegalArgumentException e) {
  12. }
  13. assertEquals(1, counterFilter.getCharactersSent());
  14. 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.

  1. when(mockFilter.read()).thenReturn("abc", "def"); // consecutive stubbing
  2. assertEquals("abc", counterFilter.read());
  3. assertEquals("def", counterFilter.read());
  4. verify(mockFilter, times(2)).read();
  5.  
  6. // demonstrates the eq match on a given object
  7. String myString = "myString";
  8. when(mockFilter.send(eq(myString))).thenReturn(1000);
  9. assertEquals(1000, counterFilter.send(myString));
  10. 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:

  1. public class CounterFilterTest {
  2.  
  3. @Mock
  4. 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:

  1. package com.ociweb.jnb.test;
  2.  
  3. import org.junit.Before;
  4. import org.mockito.MockitoAnnotations;
  5.  
  6. public class SampleBaseTestCase {
  7.  
  8. @Before public void initMocks() {
  9. MockitoAnnotations.initMocks(this);
  10. }
  11. }

Miscellaneous

Other interactions include:

  1. //verify that method was never called
  2. verify(mockOne, never()).add("two");
  3.  
  4. //verify that other mocks were not interacted
  5. verifyZeroInteractions(mockTwo, mockThree);
      verifyNoMoreInteractions(mockedObj),
      when(mock.someMethod("some arg")).thenReturn("one", "two", "three");

Tips

  1. verify(mock).someMethod(anyInt(), anyString(), eq("third argument"));
  2. // Above is correct - eq() is also an argument matcher
  3.  
  4. verify(mock).someMethod(anyInt(), anyString(), "third argument");
  5. // Above is incorrect - exception will be thrown because third argument is
  6. // given without an argument matcher.

Limitations 

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