Tutorial: Using Mockito in an integration test

Even if Mockito (see my previous post) usually helps us to cut all dependencies in our unit tests, it can be useful also in the integration tests where we often want to have all real applications layers.

Let’s assume to have the following Spring controller:

@Controller
public class LandingPageController {
  protected static final String ADMIN_MAIN = "adminMain";
  protected static final String PROVIDER_MAIN = "providerMain";
  protected static final String USER_MAIN = "userMain";
  private UserManager userManager;

  @Autowired
  public void setUserManager(final UserManager pUserManager) {
    this.userManager = pUserManager;
  }

  @RequestMapping(value = "/users")
  public ModelAndView landingPage(final HttpServletRequest request) {
    ModelAndView mav;
    final User user = userManager.getCurrentUser();
    if (user.isAdministrator()) {
      mav = new ModelAndView(new RedirectView(ADMIN_MAIN));
    } else if (utente.isProvider()) {
      mav = new ModelAndView(new RedirectView(PROVIDER_MAIN));
    } else {
      mav = new ModelAndView(new RedirectView(USER_MAIN));
    }
    return mav;
  }
}

The controller redirects the currently logged user to a proper landing page, depending on its role.

The controller could be tested with a unit test, mocking the UserManager and asserting the return values but I decided for a different test approach.

In this case, I want to check if Spring configuration is correct and if the controller method is properly invoked when we access the “/users” url.

In other words, I need an integration test which usually requires that all dependencies are real. In this case, the UserManager is already tested in other tests so it would be better to use an UserManager mock to reduce test effort and execution time.

To create an integration test for a Spring based application, I usually use the following abstract class which defines the Spring configuration to be used for test:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
  "classpath:/spring/dispatcher-servlet.xml",
  "classpath:/spring/applicationContext.xml",
  "classpath:/spring/security.xml"})
@TransactionConfiguration(transactionManager = "txManager", defaultRollback = true)
@Transactional
public abstract class IntegrationTestCase {
  @Autowired
  protected ApplicationContext applicationContext;
}

 Few comments:

  • we use the Spring specific jUnit runner (SpringJUnit4ClassRunner) to have Spring environment during the test
  • with the @ContextConfiguration annotation we define all Spring configuration files which are relevant for the tests

The integration test for our controller is the following:

public class LandingPageControllerIT extends IntegrationTestCase {

we extend the class from the IntegrationTestCase class so we can inherit all Spring configuration. Note: class (and file) name ends with IT which is the maven default for integration test files. See failsafe plugin documentation for more details.

Important: we cannot use the usual Mockito runner because we are using the Spring one, so we will not use Mockito annotations.

private static final String PAGE = "/users";
private MockHttpServletRequest request;
private MockHttpServletResponse response;
private HandlerAdapter handlerAdapter;
private LandingPageController sut;
private UserManager userManager;

MockHttpServletRequest and MockHttpServletResponse are mocking classes available in the Spring library while the HandlerAdapter is the real one because we need in the setUp method which is the following:

@Before
public void setUp() {
  sut = new LandingPageController();
  userManager = Mockito.mock(UserManager.class);
  sut.setUserManager(userManager);

  request = new MockHttpServletRequest();
  request.setRequestURI(PAGE);
  response = new MockHttpServletResponse();

  handlerAdapter = applicationContext.getBean("methodHandler", HandlerAdapter.class);
  assertThat(handlerAdapter.supports(sut)).isTrue();
}

We create the UserManager mock and inject it in the sut (System Under Test) instance using the setter.

We then create the request and response instances and set the requested page.

Finally we find the handler adapter bean as defined in the Spring application configuration. The assertThat (which is from AssertJ library) checks if the handler bean is configured to handle the controller under test. If not, there is no meaning to continue the tests (first piece of our integration test).

The first test is to check what happens when the logged user is an administrator:

@Test
public void userIsAdministrator() {
  // given
  doReturn(createAdministrator()).when(userManager).getCurrentUser();
  // when
  final ModelAndView mav = handlerAdapter.handle(request, response, sut);
  // then
  assertModelAndView(mav, LandingPageController.ADMIN_MAIN);
}

In the given section, we defined the return value for the mocked UserManager.getCurrentUser method, with the help of a private method (“createAdministrator()), see below.

In the when section, we invoke the handler which is the same method invoked by Spring when a real HTTP request reaches our application. This is the real integration test.

Finally, in the then section, we check the results, using a utility method (see below).

Similar tests (not shown) for the other types of user.

At the end we have the utility methods, to check the ModelAndView instance and to create a dummy user.

private static void assertModelAndView(final ModelAndView pMav, final String pLandingPage) {
  assertThat(pMav.getView()).isNotNull().isInstanceOf(RedirectView.class);
  final RedirectView view = (RedirectView) pMav.getView();
  assertThat(view.getUrl()).isEqualTo(pLandingPage);
}

private static User createAdministrator() {
  final User ris = new User();
  ris.setRole(“ADM”);
  return ris;
}
}

Conclusion: Mockito is very useful even if without runner and annotations.

Tutorial: using Mockito

Mockito (http://code.google.com/p/mockito/) is a Java mocking library which is very useful in unit testing but also to simplify and enhance the integration tests.

There are different situations where Mockito can be used and each situation requires a different approach and different Mockito usage.

In this tutorial I will show how I implement unit tests for middle (service, business logic) layer classes.

In the examples below I will use the Spring Framework demo project named PetClinic and available at https://github.com/spring-projects/spring-petclinic but the article contents does not depend on any Spring features.

To use Mockito I added the following dependency to the project pom.xml :

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>1.9.5</version>
    <scope>test</scope>
</dependency>

We will also use AssertJ (link):

<dependency>
    <groupId>org.assertj</groupId>
    <artifactId>assertj-core</artifactId>
    <version>1.3.0</version>
    <scope>test</scope>
</dependency>

Inside the PetClinic demo there is the ClinicService which is a Springs Service bean. The interface is org.springframework.samples.petclinic.service.ClinicService while the implementing class is org.springframework.samples.petclinic.service.ClinicServiceImpl.

The ClinicService has several dependencies to the application lower level, the DAO / Repository level:

private PetRepository petRepository;
private VetRepository vetRepository;
private OwnerRepository ownerRepository;
private VisitRepository visitRepository;

The ClinicService is tested by AbstractClinicServiceTests and its 3 different implementations (using 3 different DB access Spring solutions: direct JDBC, JPA and Spring Data).

Actually these tests are integration tests because the class under test (ClinicService) is using, during the test, its real dependencies (the repositories) and so it is not isolated.

By the way, PetClinic demo does not use the standard naming convention for the tests (at least for maven projects) which is the following:

  • *Test.java or Test*.java for unit tests (Surefire plugin)
  • *IT.java or IT*.java for integration tests (FailSafe plugin)

In PetClinic, all tests (unit and integration) are named *Tests.java (“Tests” instead of “Test”) so Surefire plugin has been customized as following:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.13</version>
    <configuration>
        <includes>
            <strong><include>**/*Tests.java</include></strong>
        </includes>
    </configuration>
</plugin>

In this tutorial, I will follow their convention even if it is not what I usually do in my projects.

Let’s unit test ClinicService with the help of jUnit and Mockito.

First step is to create the test class and instantiate the ClinicService implementation class:

public class ClinicServiceImplTests {
    private ClinicServiceImpl sut;
}

A couple of comments:

  • I use the implementing class and not the interface. Using the implementing class, let us access to the class protected methods (if any), not accessible using the interface.
  • The instance name of the class to be tested is usually sut (which stays for “system under test”) to help myself and other test code readers to easily identify the class we are testing. Cut (for “class under test”) is also used (by others) but I prefer sut because it is more generic.

We need now to instantiate the ClinicServiceImpl and, to avoid dependencies among tests, I use the jUnit before method

@Before
public void setUp() throws Exception {
    sut = new ClinicServiceImpl(petRepository, vetRepository,
        ownerRepository, visitRepository);
}

ClinicServiceImpl costructor requires the 4 repositories: we will create mocked versions of the real ones (to break the dependency between ClinicServiceImpl and the repositories).

To create the mocks:

@Mock private OwnerRepository ownerRepository;
@Mock private PetRepository petRepository;
@Mock private VetRepository vetRepository;
@Mock private VisitRepository visitRepository;

@Mock is a Mockito annotation which need a jUnit TestRunner to be activated. We should add @RunWith(MockitoJUnitRunner.class) as class annotation.

After all these changes we have

@RunWith(MockitoJUnitRunner.class)
public class ClinicServiceImplTests {
    private ClinicServiceImpl sut;
    @Mock private OwnerRepository ownerRepository;
    @Mock private PetRepository petRepository;
    @Mock private VetRepository vetRepository;
    @Mock private VisitRepository visitRepository;

    @Before
    public void setUp() throws Exception {
        sut = new ClinicServiceImpl(petRepository, vetRepository,
            ownerRepository, visitRepository);
    }
}

One important comment to do is that we are NOT using any Spring features (like @Autowire or @ContextConfiguration) in the test. We do not depend on Spring and we will also enjoy a faster test execution because Spring framework will not be loaded.

Spring allows us to use setter to inject repositories as alternative to constructor injection used in the demo. For example we could have in the implementation class something like the following:

private OwnerRepository ownerRepository;
.... other fields
@Autowired
public void setOwnerRepository(OwnerRepository pOwnerRepository) {
    this.ownerRepository = pOwnerRepository;
}
..... other setters

In this case, in the test setup method we will have:

sut = new ClinicaServiceImpl();
sut.setOwnerRepository(ownerRepository);
.....other calls to sut setters

We are ready now to test ClinicServiceImpl (our sut) behaviour.

Let’s start with a ClinicServiceImpl method which is a good (even if very simple) example of a method which receives data from one of its dependencies (ownerRepository in this case).

Method (from ClinicServiceImpl) is

public Owner findOwnerById(int id) throws DataAccessException {
    return ownerRepository.findById(id);
}

Following my TDD habits, the test is:

/**
* Pet owner can be found using its ID
*/
@Test
public void findPetOwnerById() {
    // given
    final int id = 123;
    Mockito.doReturn(createOwner()).when(ownerRepository).findById(id);
    // when
    final Owner res = sut.findOwnerById(id);
    // then
    assertThat(res).isNotNull();
}
private static Owner createOwner() {
    return new Owner();
}

Comments:

  • the method comment helps to clarify the purpose of the test which should be also reported in the method name. Thankfully, there is no more need to use old jUnit 3 “test***” naming convention.
  • the test method body is divided in three sections:
    • given: all data (test fixture) preparation
    • when : method to be checked invocation
    • then : checks and assertions
  • createOwner() is a support private method to create a very basic Owner.
  • in the when section I usually name the result of the method (if not void) as “res” (result). Again this is to make test code clearer.
  • in the then section I usually uses AssertJ fluent assertion library. See here for more details about AssertJ library. We will see later how Assertj let us to be more efficient in our verification step.
  • findOwnerById() does not change the Owner instance returned by ownerRepository so there is no meaning to check Owner fields value. In other cases, I use more detailed assertions (like assertThat(res.getId()).isEqualTo(123)) than the isNotNull().

The key element is here is the line:

Mockito.doReturn(createOwner()).when(ownerRepository).findById(id);

which says:

dear Mockito, during the test execution, when someone (the findOwnerById method in our case) will invoke the ownerRepository.findById() method with int 123 as argument, please return the Owner instance created by createOwner()

Without this line, ownerRepository.findById() will return null. This is the standard behavior for Mockito.

Specifying the int value (123) will let us to filter ownerRepository.findById() invocations:

  • ownerRepository.findById(123) with return a not null Owner
  • ownerRepository.findById(44) will return a null

If we cannot be so accurate about the argument (for example, when method argument is calculated by the method under test), we can use

Mockito.doReturn(createOwner()).when(ownerRepository).findById(Mockito.anyInt());

to say Mockito to return a not null Owner regardless the findById parameter value.

Let’s now test another method from ClinicServiceImpl which send data to a dependency:

public void savePet(Pet pet) throws DataAccessException {
    petRepository.save(pet);
}

The test is :

@Test
public void savePet() {
    // given
    final Pet pet = createPet();
    // when
    sut.savePet(pet);
    // then
    Mockito.verify(petRepository, Mockito.times(1)).save(pet);
}
private static Pet createPet() {
    Pet pet = new Pet();
    pet.setName("My little Pet");
    return pet;
}

The structure is the same but here we use Mockito for a different purpose: to check if a method is invoked or not and how many times.

The line

Mockito.verify(petRepository, Mockito.times(1)).save(pet);

says:

Dear Mockito, please check during the test execution, that petRepository.save() will be invoked one time (no zero, no more than one) and with the argument pet (as it is created by the createPet() support method).

If the method petRepository.save() is not invoked or invoked more than one times or invoked with a different pet, verify will rise a test failure exception.

Comment: Mockito.times(1) is the default so we can write the same line as

Mockito.verify(petRepository).save(pet);

Do not be confused by the fact that Mockito.verify is specified in the then section, after the petRepository.save() invocation (in the when section). Mockito always collect all methods invocation data. The verify istruction just compare what happened with what we expect.

Now we can move to a more complicated example but the ClinicService is too simply. Let me add to it the following method:

@Override
@Transactional
public void adoptAPet(Owner owner, Pet pet) {
    if (pet != null) {
        owner.addPet(pet);
        ownerRepository.save(owner);
    }
}

The method let an owner to adopt a pet.

Its test can be:

/**
* Pet adoption with a real pet
*/
@Test
public void petAdoptionWithRealPet() {
    // given
    final Owner owner = createOwner();
    final Pet pet = createPet();
    final ArgumentCaptor<Owner> ownerCaptor = ArgumentCaptor.forClass(Owner.class);
    // when
    sut.adoptAPet(owner, pet);
    // then
    Mockito.verify(ownerRepository).save(ownerCaptor.capture());
    assertThat(ownerCaptor.getValue().getPets()).hasSize(1).contains(pet);
}

We want now to find which is the argument of the ownerRepository.save() invocation inside the adoptAPet() body. In other words we want to intercept the call to ownerRepository.save() and get the value of its argument.

This is a three steps approach.

First step is to prepare a dedicated parameters captor (something that will capture the method argument) with:

ArgumentCaptor<Owner> ownerCaptor = ArgumentCaptor.forClass(Owner.class);

where Owner is the ownerRepository.save() argument type.

Second step is to ask verify to save the parameter value in our captor with the following line:

Mockito.verify(ownerRepository).save(ownerCaptor.capture());

Verify will not only check if the ownerRepository.save() is invoked only once but also it will save its argument value (with the captor capture() method).

Final step is to get the captured argument value using the ownerCaptor.getValue() method (which in our case returns the Owner instance used to invoke ownerRepository.save()) and to assert its contents.

In the test I used AssertJ power to check if owner.getPets() collection has size 1 and contains the same pet I passed to the adoptAPet() (when section):

assertThat(ownerCaptor.getValue().getPets()).hasSize(1).contains(pet);

The ArgumentCapture is a very powerful tool which let us to get internal data if used as method argument to mocked dependencies.

The adoptAPet() method handles the null case for the pet parameter so let’s test this behavior:

/**
* Pet adoption do nothing if pet is null
*/
@Test
public void petAdoptionWithNullPet() {
    // given
    final Pet pet = null;
    final Owner owner = createOwner();
    // when
    sut.adoptAPet(owner, pet);
    // then
    //Mockito.verify(ownerRepository, Mockito.never()).save(Mockito.any(Owner.class));
    // or
    Mockito.verifyZeroInteractions(ownerRepository);
}

Here we want to be sure that ownerRepository.save() is not invoked when the pet parameter is null.

Two different solutions are possible: we can verify that the ownerRepository has not been used (which means none of its method has been used) with the following:

Mockito.verifyZeroInteractions(ownerRepository);

or verify that the ownerRepository.save() is never invoked with the following:

Mockito.verify(ownerRepository, Mockito.never()).save(Mockito.any(Owner.class));

leaving the possibility that other ownerRepository methods can be invoked. In this case, I can use Mockito.any(Owner.class) as save() parameter because here the save() argument value is not important.

This tutorial has shown different ways to use Mockito (and AssertJ) to create a unit test for a middle layer class. The ClinicServiceImpl class was intrinsically testable and we could easily break its dependencies without code refactoring.

This is not always the case. In future articles I will show how I handle difficult to test classes and also how Mockito can help in integration tests.

Final comment is how I have used Mockito in the above examples: I did not use static imports to help you to identify Mockito instructions but please be aware that all instructions can be shortened. For example

Mockito.verify(ownerRepository, Mockito.never()).save(Mockito.any(Owner.class));

becomes

verify(ownerRepository, never()).save(any(Owner.class));

with the proper static imports. Ask your preferred IDE to help you.

All files I have modified/added to the PetClinic application can be found here.