Tutorial: Java abstract classes testing

In Java, abstract classes are used to define the interface of the class, with a list of (abstract) methods to be implemented by the extending class; basically what it is also possible to have with the “real” interfaces, the one defined with the interface instruction.

One significant difference between abstract classes and interfaces is that abstract classes can also have fields and non abstract methods which contain logic.

Abstract classes with code (in non abstract methods) are common in some design patterns implementations and in class hierarchy based frameworks. This is a typical solution to share code inside a class family.

Of course this code should be tested but abstract classes cannot be instantiated.

In this tutorial, we will analyze several cases and all possible alternative solutions to test abstract classes with non abstract methods. Let’s start with the libraries we will use on our tests (all Java 6 source level):

Few important remarks:

  1. Some solutions are based on Mockito version 1.10.12 or above but these versions are not compatible with the latest PowerMock version (1.6.1, see here).
    So in the project we will use two different libraries sets:

    1. Classic: jUnit 4.12, Mockito 1.10.8, PowerMock 1.6.1
    2. Latest: jUnit 4.12, Mockito 1.10.19 (no PowerMock)
  2. All examples are based on the “classic” combination except few ones marked with a special comment. In the project pom.xml, both dependencies sets are defined but one is commented out. Please note that, due to the combinations differences, some tests cannot be compiled in all combinations.
  3. Complete project can be found at https://github.com/gualtierotesta/test-solutions
  4. The examples are not real world code. The code has been kept at the minimum in order to better show the adopted testing strategy.
  5. A basic knowledge about Java unit testing and jUnit framework is needed for a more complete understanding of the examples. Mockito and PowerMock knowledge is not required.
  6. Have also a look at the Test Glossary for the meaning of several test terms used in this post.

CASE 1: independent method

This is the simplest case: the abstract class contains, in addition to abstract methods, a public non abstract method (named “methodToBeTested” in our examples) with no internal dependencies: it does not call any other method in its class.

public abstract class AbstractCase1 {
    public abstract int myAbstractMethod();
    public String methodToBeTested() {
        return "CASE-1";
    }
}

We want to test the logic of the method “methodToBeTested()”. We have three possible testing solutions:

Solution 1.A Using a concrete class

We create a concrete class which extends the abstract class and test the method from this class.

Our test class body:

     private class ConcreteCase1 extends AbstractCase1 {
        @Override
        public int myAbstractMethod() {
            return 0;  //Dummy implementation
        }
    }

    @Test
    public void testUsingConcreteClass() {
        // given
        ConcreteCase1 sut = new ConcreteCase1();
        // when
        String result = sut.methodToBeTested();
        // then
        Assert.assertEquals("CASE-1", result);
    }

Explanation:

  • Line 1: we define a concrete implementation of the abstract class where all abstract methods have a dummy implementation; they are not used so we don’t care.
  • Line 11: we create an instance named “sut” (system under test) of the concrete class. Through this instance we have free access to the method we want to test

The only drawback of this solution is the need to create the concrete class and created a dummy implementation for all abstract methods.

The given, when and then comments are used to separated different test phases: preparation, execution and results analysis. See also http://martinfowler.com/bliki/GivenWhenThen.html

Solution 1.B Using a Mockito spy (Mockito 1.10.12+ required)

We can use Mockito to create a spy instance of the abstract class. A spy is a class instance with standard behavior but that can be controlled by Mockito; for example we can ask Mockito to change the normal method return value, bypassing the return value calculated by the method body. See also the Testing Glossary.

In our case, we use a Mockito spy only because it let us create an abstract class instance, which is normally not possible. This is not a typical Mockito spy use case.

    @Test
    public void testUsingMockitoSpy() {
        // given
        AbstractCase1 sut = Mockito.spy(AbstractCase1.class);
        // when
        String result = sut.methodToBeTested();
        // then
        Assert.assertEquals("CASE-1", result);
    }

Explanation:

  • line 4: create the spy instance using Mockito.spy(class) method.
  • line 6: invoke the method to be tested

The main drawback of this solution is that Mockito.spy() will invoke the abstract class constructor during spy instance creation. In some cases the constructor uses external dependencies which can be an obstacle to our unit test executions. These kind of dependencies are usually called “test impediments”.

Solution 1.C Using Mockito mock

If you cannot use latest Mockito version or the abstract class constructor contains some test impediments, we can use Mockito to create a mock.

In general mocking is used to “empty” a class from its logic: a mocked instance does not have code insides the methods. In our case, we create a mock and then ask Mockito to restore the code inside the method we want to test.

This is not a very clean solution but it works.

    @Test
    public void testUsingMockitoMock() {
        // given
        AbstractCase1 sut = Mockito.mock(AbstractCase1.class);
        Mockito.doCallRealMethod().when(sut).methodToBeTested();
        // when
        String result = sut.methodToBeTested();
        // then
        Assert.assertEquals("CASE-1", result);
    }

Explanation:

  • line 4: create the mocked instance using Mockito.mock(class) method.
  • line 5: we ask Mockito to use real (=original) code when method is invoked

CASE 2: independent method with test impediment

In this second use case, the method we want to test calls a private method which contains a test impediment. We cannot simply execute the method to be tested because first we need to disable the test impediment method.

  public abstract class AbstractCase2 {

    public abstract int myAbstractMethod();

    public String methodToBeTested() {
        return prefix() + "2";
    }

    // Test impediment
    private String prefix() {
        return "CASE-";
    }
}

In our example, the method to be tested calls the private method “prefix()”. Note: the method body in the example is NOT a test impediment as it just returns a string. In the real world, the method performs some time and/or resource consuming tasks which should be avoided in our unit tests.
We want to “remove” prefix() standard behavior but to do this we cannot create a concrete class because private methods cannot be overridden. We cannot even use Mockito because it cannot control private (and, by the way, also static ) methods so we will use its stronger companion: PoweMock.

Solution 2.A Using PowerMock
The test class:

@RunWith(PowerMockRunner.class)
@PrepareForTest(AbstractCase2.class)
public class AbstractCase2Test {

    @Test
    public void testWithPowerMock() throws Exception {
        // given
        AbstractCase2 sut = PowerMockito.mock(AbstractCase2.class);
        PowerMockito.doCallRealMethod().when(sut).methodToBeTested();
        PowerMockito.doReturn("TESTCASE-").when(sut, "prefix");
        // when
        String result = sut.methodToBeTested();
        // then
        Assert.assertEquals("TESTCASE-2", result);
    }
}

Explanation:

  • line 1: the @RunWith annotation defines PowerMock as the runner for the test
  • line 2: the @PrepareForTest(class) annotation asks PowerMock to prepare the class for later processing
  • line 8: we create a mock using PowerMockito.mock() which, in turns, call the Mockito mock() method
  • line 9: as we did for the first use case, we ask PowerMock to re-enable the body of the method to be tested
  • line 10: here it is the key element of this test: we ask PowerMock to stub the private method return value so we can test methodToBeTested() without test impediments. Mockito alone cannot do this stub. Please note that the name of the private method, prefix, is passed to PowerMock as string because it is not accessible from outside. PowerMock will use reflection to find it.

CASE 3: method which access instance fields
Abstract classes can have an internal state implemented with class fields. The value of the fields can be significant for the test so we need a way to control them in order to define the initial test context (the “test fixture”).
If the field is public (uh, not very nice OO solution) or protected, it can be freely accessed (and modified) from our test class. But if it is private, we have few options to control it.
Let’s start with the example class:

  public abstract class AbstractCase3 {

    protected boolean type = false;
    private int count;

    public abstract int myAbstractMethod();

    public String methodToBeTested() {
        String res;
        count += 1;
        if (count > 10) {
            res = "Too many times";
        } else {
            if (type) {
                res = "Type is true";
            } else {
                res = "Type is false";
            }
        }
        return res;
    }
}

Two class fields, type and count, control the methodToBeTested() behavior. Note: this is just an example so forgive the meaningless logic.

Solution 3.A Using Mockito mock
This solution is identical to solution 1.C: we create a mock and then later we ask Mockito to re-enable the method body.

    @Test
    public void testTrueTypeWithCountLessThen10() {
        // given
        AbstractCase3 sut = Mockito.mock(AbstractCase3.class);
        Mockito.doCallRealMethod().when(sut).methodToBeTested();
        sut.type = true;
        // when
        String result = sut.methodToBeTested();
        // then
        Assert.assertEquals("Type is true", result);
    } 

Explanation:

  • line 4: create the mocked instance using Mockito.mock(class) method.
  • line 5: we ask Mockito to use real (=original) code when method is invoked
  • line 6: we fix the type field value to be true so we can test the method in this specific condition

As shown, we cannot control the count field value with this kind of solution.

Solution 3.B Using Mockito mock and a setter
Like the solution 3.A but we add a count field setter to the abstract class (not to the test class !) so we can control its value from the test class.

In the abstract class code we add the following lines:

    // Only for test
    void setCount(int pAmount) {
        this.count = pAmount;
    }

This solution is identical to solution 1.C: we create a mock and then later we ask Mockito to re-enable the method body.

    @Test
    public void testCountGreaterThen10WithSetter() {
        // given
        AbstractCase3 sut = Mockito.mock(AbstractCase3.class);
        Mockito.doCallRealMethod().when(sut).methodToBeTested();
        Mockito.doCallRealMethod().when(sut).setCount(Mockito.anyInt());
        sut.setCount(15);
        // when
        String result = sut.methodToBeTested();
        // then
        Assert.assertEquals("Too many times", result);
    } 

Explanation:

  • line 4: create the mocked instance using Mockito.mock(class) method.
  • line 5 and 6: we ask Mockito to use real (=original) code when method is invoked and also for the setter. Note the Mockito.anyInt() call which defines for which value (all, in this specific case) the real method body should be used
  • line 7: we call the count setter with a value, 15, above the condition defined inside the method (10) so we can test this code path

Of course we could also change type field value like we did in the previous solution.

Solution 3.C Using PowerMockito
If we cannot add the setter, for example because abstract class source code cannot be touched, we can use PowerMock to change class fields.

   
    @Test
    public void testWithPowerMock() {
        // given
        AbstractCase3 sut = PowerMockito.mock(AbstractCase3.class);
        PowerMockito.doCallRealMethod().when(sut).methodToBeTested();
        Whitebox.setInternalState(sut, "count", 15);
        // when
        String result = sut.methodToBeTested();
        // then
        Assert.assertEquals("Too many times", result);
    }

Explanation:

  • line 6: PowerMock Whitebox class uses reflection to control internal class contents. In our case we change to 15 the value of the count field (second argument, which should be noted it is a string).

Using Whitebox is not very common and it should be considered only for very untestable code only.

CASE 4: method which call abstract methods
This is the typical case, for example, of the Template Method design pattern (http://en.wikipedia.org/wiki/Template_method_pattern) but also other design patterns and frameworks use this solution. The non abstract method defines the global flow while the abstract method can be implemented in different ways to customize the behavior.

   public abstract class AbstractCase4 {

    public abstract int myAbstractMethod();

    public String methodToBeTested() {
        int val = myAbstractMethod();
        return "CASE-" + val;
    }
}

At line 6, the abstract method is invoked.

To test this code, we have three different solutions: extending the abstract class, using Mockito to create a mock or a spy.

Solution 4.A Using a concrete class
We can extend the abstract class, giving a convenient (for testing purposes) behavior to the abstract method:

   
    private class ConcreteCase4 extends AbstractCase4 {
        @Override
        public int myAbstractMethod() {
            return 4;  //Dummy implementation
        }
    }

    @Test
    public void testUsingConcreteClass() {
        // given
        AbstractCase4Test.ConcreteCase4 sut = new AbstractCase4Test.ConcreteCase4();
        // when
        String result = sut.methodToBeTested();
        // then
        Assert.assertEquals("CASE-4", result);
    }

Explanation:

  • line 1: ConcreteClass4 extends the AbstractClass4Test and gives a convenient implementation of the abstract methods.

Solution 4.B Using a mock with Mockito
We create a mock and we stub the abstract method:

    @Test
    public void testUsingMockitoMock() {
        // given
        AbstractCase4 sut = Mockito.mock(AbstractCase4.class);
        Mockito.doCallRealMethod().when(sut).methodToBeTested();
        Mockito.doReturn(4).when(sut).myAbstractMethod();
        // when
        String result = sut.methodToBeTested();
        // then
        Assert.assertEquals("CASE-4", result);
    }

Explanation:

  • line 6: the abstract method is stubbed with the return value we prefer for the test. Please note that, thanks to Mockito, we are stubbing a method which does not have any implementation (because it is abstract).

Solution 4.C Using a spy with Mockito (Mockito 1.10.12+ required)
Very similar to the previous use case:

   
  @Test
  public void testUsingMockitoSpy() {
        // given
        AbstractCase4 sut = Mockito.spy(AbstractCase4.class);
        Mockito.doReturn(4).when(sut).myAbstractMethod();
        // when
        String result = sut.methodToBeTested();
        // then
        Assert.assertEquals("CASE-4", result);
}

Explanation:

  • line 5: the abstract method is stubbed with the return value we prefer for the test. Please note that, thanks to Mockito, we are stubbing a method which does not have any implementation (because it is abstract).

CONCLUSIONS

Abstract classes code can present a not so short list of use cases. Each of them can be tested using different techniques and different test support libraries.

In this tutorial we went through many examples which hopefully cover many real worlds cases. If not, just let me know so I can extend this post.

 

Advertisements

Mockito is back !

Mockito is back with a new release (1.10.x), after almost two years from the last official release (the well-known and loved 1.9.5).

Several 1.10 updates have come out after the 1.10.0 released at the end of this September.

Mockito 1.10.x includes several improvements and cleanups. Interesting is the possibility to create light-weight mocks and the BDD “then” support .

Release notes here.

Thanks to Szczepan Faber and the rest of the team for their wonderful job.

Review: Mockito Cookbook

Mockito Cookbook
Mockito Cookbook by Marcin Grzejszczak
My rating: 5 of 5 stars

Very good. This is a well written and very interesting reading for everybody involved in Java testing. This book is not intended to be a primer on testing in general and on Mockito in particular. Beginners should look for an introduction on automated testing before start with Mockito Cookbook. The author covers everything related to the Mockito library and also on several additional libraries and tools connected to Mockito, like, for example, PowerMock. The book starts with an introductive chapter on Mockito installation and basic usage with both JUnit and TestNG. The core of the book is the chapters from 2 to 7 where the author explain, as recipes, several techniques to test easy and difficult to test code. Final book chapters are on legacy code testing, testing using frameworks like Spring and Mockito compared to other mocking libraries. In all examples, sometimes a bit repetitive due to the recipes approach, the author also explain general testing and object oriented programming approaches and methodologies. This is of course limited in space but there are plenty of references.

View all my reviews

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.

“Instant Mockito” review

I have recently read “Instant Mockito” by Marcin Grzejszczak. Good reading.

I use Mockito every day but, nevertheless, the book could give me hints and ideas on how to improve Mockito usage in my projects. For example, I discovered the @InjectMocks annotation and several special arguments matchers I did not know before.

I suggest the book to all experienced programmers.

The book is not a Mockito primer nor it is a tutorial on unit testing techniques. The author assumes you know already how (and why) to do unit testing. Beginners should better start with more introductive books.

Mockito methods are not documented in detail; you should refer to official Mockito documentation for a complete reference (all relevant links can be found at the end of the book).

The first part of the book explains what is Mockito, how to install it in projects based on Maven and other dependency managers and a shows quick start example. Short but the essential is in.

The second part is the most interesting (at least for me) with the section named “Top 8 features you need to know about” which is basically a Mockito showcase: the author describes, by examples, several use cases using almost all Mockito features.

Among them: void methods stubbing, method calls counting, exceptions handling, method arguments capture, legacy code spying and annotations usage.

The book ends with references to Mockito resources available on the Net: web sites, Twitter accounts, blogs, communities.

(Available from Packt Publishing)

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.