Unit Testing with Mockito

In this tutorial, we are going to explain using Mockito with JUnit. We will describe why mocking is necessary, go over some examples and at the end, we will list the limitations of Mockito.

Before beginning to read this tutorial you should be familiar with the general concepts of JUnit and Maven. If you are not comfortable with JUnit you may want to start with learning JUnit. http://www.swtestacademy.com/junit-tutorial/

What is Mocking?

So let’s start with the definition. To put simply, mocking means faking or imitating the original. When we are talking about mocking in unit testing it means that we are simulating a system. In terms of unit testing, the thing we are simulating is a class most of the time.

Why do we need mocking?

It may be easy to write your unit tests when you are working with independent, isolated classes which work on their own. Unfortunately, that is not the case when it comes to the real world. Most of the system’s classes are dependant on each other or they reach resources that you can’t reach locally. These characteristics push you to use mocking so that you can write your tests in an isolated environment where your only concern would be the class that you are currently working on.

Maven dependencies

Now that we have defined what is mocking and why mocking is needed, it is time to write some code. To begin using mockito we have to add the following dependency to our pom.xml file.

<dependency>
   <groupId>org.mockito</groupId>
   <artifactId>mockito-all</artifactId>
   <version>1.10.19</version>
   <scope>test</scope>
</dependency>

By the time this tutorial is written the latest stable version is 1.10.19. There is the second version of mockito out there but they are still in beta so we will not be using that.

One detail that I want to mention here is the scope of the dependency. The scope test means that the mockito jar will only be included when you are running your tests and it would not be included when you package your application so that using mockito would not increase the file size of your jar file in the production environment.

We will also be using the JUnit library. I am adding that also so that when you copy the codes you will have a running application at your hands.

<dependency>
   <groupId>org.junit.jupiter</groupId>
   <artifactId>junit-jupiter-api</artifactId>
   <version>5.3.1</version>
   <scope>test</scope>
</dependency>

Creating and using Mock Objects

There are two ways to create a mock object

  • Using the @Mock annotation
  • Using the static mock() function

Let’s start with the first one.

We will start with a simple model class, Person here, which will only have name and age as members.

public class Person {

   private String name;
   private int age;

   public Person(String name, int age) {
       this.name = name;
       this.age = age;
   }

   public String getName() {
       return name;
   }

   public int getAge() {
       return age;
   }
}

This is so simple right. And now let’s say we have a DAO for this class which connects to a database and gets the Person object from there.

public class PeopleDAO {
   public Person getPeopleById(long id){
       return null;
   }
}

For simplicity our DAO class does not return concrete Person object for now, it just returns null. But in the real world, you may assume that this class connects to a database, queries the people table with id and returns the resulting object. Now let’s go and write our first mock example.

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

public class MockWithAnnotation {

   @Mock
   PeopleDAO peopleDAO;

   @BeforeEach
   public void setup() {
       MockitoAnnotations.initMocks(this);
   }

   @Test
   public void testPeopleDAO(){

       Mockito.when(peopleDAO.getPeopleById(1)).thenReturn(new Person("John Doe", 21));

       Person p = peopleDAO.getPeopleById(1);

       assert (p.getName().equals("John Doe"));
       assert (p.getAge() == 21);
   }
}

Now let’s explain what we did here. We mocked a peopleDAO instance so when we ask the person with id = 1 it would return “John Doe” with age 21. Then we check whether the mocking does work or not by checking the method getPeoplebyId(1).

Now, this was the first way to do mocking, by @Mock annotation. Now let’s go ahead and see the usage of the mock() method.

import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

public class MockWithMethod {

   @Test
   public void testPeopleDAO(){

       PeopleDAO peopleDAO = Mockito.mock(PeopleDAO.class);

       Mockito.when(peopleDAO.getPeopleById(1)).thenReturn(new Person("John Doe", 21));

       Person p = peopleDAO.getPeopleById(1);

       assert (p.getName().equals("John Doe"));
       assert (p.getAge() == 21);
   }
}

What this code does is the same as the previous one. We just used the mock method this time.

Now we are ready to see what else can be done with mockito. First, let’s go ahead one simple step and make the mock object return values depending on the parameters given.

import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

public class MockWithMethod {

   @Test
   public void testPeopleDAO(){

       PeopleDAO peopleDAO = Mockito.mock(PeopleDAO.class);

       Mockito.when(peopleDAO.getPeopleById(1)).thenReturn(new Person("John Doe", 21));
       Mockito.when(peopleDAO.getPeopleById(2)).thenReturn(new Person("Emma Alby", 24));

       Person p = peopleDAO.getPeopleById(1);

       assert (p.getName().equals("John Doe"));
       assert (p.getAge() == 21);

       Person p2 = peopleDAO.getPeopleById(2);

       assert (p2.getName().equals("Emma Alby"));
       assert (p2.getAge() == 24);
   }
}

Now our mock object returns two different values depending on the parameters given. But what if we want to return the same object independent of the parameter that has been given. Let’s see

import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

public class MockWithMethod {

   @Test
   public void testPeopleDAO(){

       PeopleDAO peopleDAO = Mockito.mock(PeopleDAO.class);

       Mockito.when(peopleDAO.getPeopleById(Mockito.anyLong())).thenReturn(new Person("John Doe", 21));

       Person p = peopleDAO.getPeopleById(81723212L);

       assert (p.getName().equals("John Doe"));
       assert (p.getAge() == 21);

       Person p2 = peopleDAO.getPeopleById(9112L);

       assert (p2.getName().equals("John Doe"));
       assert (p2.getAge() == 21);
   }
}

Mockito.anyLong() does the job here. I should also note that Mockito has these anyX methods for all simple data types such as Mockito.anyString() and Mockito.anyBoolean().

Now let’s do something a bit different and make our mock object throw an exception.

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

public class MockWithMethod {

   @Test
   public void testPeopleDAO(){

       PeopleDAO peopleDAO = Mockito.mock(PeopleDAO.class);

       Mockito.when(peopleDAO.getPeopleById(1_000_000L)).thenThrow(new IllegalArgumentException());

       Assertions.assertThrows(IllegalArgumentException.class, () -> peopleDAO.getPeopleById(1_000_000L));
   }
}

In this example, our mock object throws IllegalArgumentException when we try to get the person with id = 1.000.000. Assertion.assertThrows verifies that when we call the method IllegalArgumentException is thrown.

Spying Objects

At this point, we know how to mock objects. But now I’ll try something slightly different. I will add another function to PeopleDAO.

public class PeopleDAO {

   public Person getPeopleById(long id){
       return null;
   }

   public Person getPeopleByName(String name){
       return new Person("Tony Stark", 35);
   }
}

I added the getPeopleByName method. This is not a real-world method as it always returns the same instance “Tony Stark”. Now let’s check my new method as following

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

public class MockWithMethod {

   @Test
   public void testPeopleDAO(){

       PeopleDAO peopleDAO = Mockito.mock(PeopleDAO.class);

       Person p = peopleDAO.getPeopleByName("");

       System.out.println(p.getName());
   }
}

I am trying to get “Tony Stark” here. Now let’s see what happens when we run this code.

java.lang.NullPointerException

There is something wrong here. The problem with mocking is you have to mock every method that the class you are mocking implements. This is not the expected behavior. We want to mock only the single method we are testing. We want all other methods to work as they are.

We need to use Spy to solve this problem.

import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

public class MockWithMethod {

   @Test
   public void testPeopleDAO(){

       PeopleDAO peopleDAO = new PeopleDAO();

       PeopleDAO spiedDAO = Mockito.spy(peopleDAO);

       Mockito.when(spiedDAO.getPeopleById(Mockito.anyLong())).thenReturn(new Person("Jon Doe", 21));

       Person p = spiedDAO.getPeopleByName("any name");

       System.out.println(p.getName());

       Person p2 = spiedDAO.getPeopleById(100);

       System.out.println(p2.getName());
   }
}

Now what we did here is to create a spied copy of PeopleDAO. I can override the getPeopleById() method in the spied object but the method getPeopleByName() remains to work as it was implemented.

Verifying Method Calls

Another handy feature of Mockito is checking whether method calls were made or not. You can even verify the number of calls or verify that the method was never called. Let’s see an example.

import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

public class MockWithMethod {

   @Test
   public void testPeopleDAO(){

       PeopleDAO peopleDAO = Mockito.mock(PeopleDAO.class);

       Mockito.when(peopleDAO.getPeopleById(Mockito.anyLong())).thenReturn(new Person("John Doe", 21));

       Person p = peopleDAO.getPeopleById(1);
       Person p2 = peopleDAO.getPeopleById(2);

       // check whether this method is called twice.
       Mockito.verify(peopleDAO, Mockito.times(2)).getPeopleById(Mockito.anyLong());

       // check whether the getPeopleByName is never called.
       Mockito.verify(peopleDAO, Mockito.never()).getPeopleByName(Mockito.anyString());
   }
}

As you may well see, we can check whether a method is called X times or never called. You may also go ahead check whether some method is used at least X times by using Mockito.atLeast(X), or at most Y times as Mockito.atMost(Y).

Conclusion and Limitations of Mockito

Although Mockito is very effective, it has a few limitations. You can not mock final classes and static methods. To overcome these shortcomings there is Powermock.

As you may see Mockito is quite handy when writing your tests. It is easy and its learning curve is almost flat. For more information on its features and more examples, you may check the following links:  Mockito web site

Thanks.
Aykut Akinci

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.