TestAutomation

Unit Testing, Mockito

This is the fourth part in the series about Unit Testing. It continues after Unit Testing, Mocking.

Mockito is a mocking framework that tastes really good. It lets you write beautiful tests with a clean & simple API. Mockito doesn’t give you hangover because the tests are very readable and they produce clean verification errors.
Mockito adds a lot of functionality to Junit.

  • Mock, Mockito can mock both interface and concrete classes
  • Spy, Mockito supports test spies
  • Matchers, Mockito supports argument matchers
  • Verification, Mockito can verify Mock interactions
  • Order, Mockito can verify Mock methods are called in order
  • Void, Mockito supports void methods
  • Final, as of Mockito 2, it is possible to mock final classes and methods

There are also some areas where Mockito falls short.

  • Private, Mockito cannot mock private methods
  • Static, Mockito cannot mock static classes
  • Equals, Mockito cannot mock the equals method
  • HashCode, Mockito cannot mock the hashCode method

Writing a unit test with Junit and Mockito

Writing a unit test with Junit and Mockito is very simple and the main Mockito site has very good documentation, see the link to the official Mockito website in the Links section.

Initialisation

To enable a testcase for Mockito in JUnit5, an extension needs to be added to the class. This extension prepares Mockito.

@ExtendWith(MockitoExtension.class)

Test

After initializing the test case with the MockitoExtension it is possible to start mocking actual classes. This is done by first initializing the mocked class with the @Mock annotation. Then the mocked class can be prepared for testing. After the test, the mocked class can be verified.

Let’s expand the earlier example with some Mockito.

Example

The example below can be found on Github.

@Mock
private PersonService mockedPersonService;

@Test
public void testGetPersonByName() throws Exception {
    // Given
    Person person = new Person();
    person.setFirstName("firstName");
    person.setLastName("lastName");

    // normally, you would set this next call up with the exact string used in the getPersonByName.
    when(mockedPersonService.getPersonByName(anyString(), anyString())).thenReturn(person);

    // When
    Person result = personHandler.getPersonByName("firstName", "lastName");

    // Then
    // When setting up the when() call with the exact strings used in the getPersonByName, this call is not needed.
    verify(mockedPersonService).getPersonByName("firstName", "lastName");
    assertNotNull(result);
    assertEquals("firstName", result.getFirstName());
    assertEquals("lastName", result.getLastName());
}

This example adds a new private field to the testCase, mockedPersonService. This private field is declared as a mock via the @Mock annotation.
Somewhere in the testcase, this gets inserted into the personHandler. How this is done is explained in detail in the next section. The test method itself now tests if the person is correctly retrieved from the PersonHandler. Internally, the PersonHandler should do this by requesting the person from the PersonService by name. This is the method that is being mocked in the Given part of the unit test.
In this example it is also verified that the mocked method is actually called. It is usually better to just test the outcome though.

Inserting Mocks

After a Mock has been created it needs to be inserted into the class under test. How to go about this depends on the implementation of the class under test.

Constructor

If the class under test has a constructor which takes the mocked class as input, this constructor can be used in the setup method of the unit test. This is usually done in a setup method. This setup method is annotated with @Before as explained in Unit Testing, JUnit

Example

The example below can be found on Github.

@Mock
private PersonService mockedPersonService;

private PersonHandler personHandler;

@Before public void setup() {
     personHandler = new  personHandler (mockedPersonService);
}

Setter

If the class under test has a setter for the mocked class, this setter can be used in the setup method of the unit test. This is usually done in a setup method. This setup method is annotated with @Before as explained in Unit Testing, JUnit

Example

The example below can be found on Github.

@Mock
private PersonService mockedPersonService;

private PersonHandler personHandler;

@Before
public void setup() {
    personHandler = new PersonHandler();
    personHandler.setPersonService(mockedPersonService);
}

Dependency Injection

Dependency injection with Mockito can be done by adding the @InjectMocks annotation on the class under test. This dependency will automatically instantiate the class under test using the default constructor after which the mocks are inserted using reflection.

Example

The example below can be found on Github.

@Mock
private PersonService mockedPersonService;

@InjectMocks
private PersonHandler personHandler;

Instantiation

When the Mocked class is instantiated inside the class under test, Mockito has no way to insert the Mocked class at that point. This can be done with PowerMock however. PowerMock will be explained in the next part of the series.

Test specific code

When neither a constructor nor a setter is present for the Mock it is tempting to write either a constructor or a setter specifically for the purpose of inserting the Mock.

Adding code to the class under test which is only ever used by the unit test should be avoided at all times since this code will end up in production. Having unused code in production is a code smell and should be avoided.

Instead, look at the way the Mocked class is actually inserted into the class under test and see if a way can be found to insert the mock at that point.

Mock Chaining

At times, code uses constrictions where multiple method calls are chained together. When using mocks, this can quickly reach a point where testcases
are hard to read and difficult to maintain. To remedy this, it is often a good idea to move the call chain into either a separate utility class. This way it becomes possible to mock just that one method call instead of having to mock every step in the call chain. This makes for much cleaner and maintainable unit tests. As an added benefit, it also makes the actual code more readable.

Tips & Tricks

  • Avoid mock chaining
  • Use mocks only when needed
  • Prefer assert over verify
  • Avoid adding code to the class under test which is only ever used by test cases

Links

More in-depth resources about Mockito can be found on the official Mockito website at https://site.mockito.org/

The examples used in this tutorial can be found on Github.