How to use Mockito to test the behavior of a Java application - in a nutshell

Posted on Oct 24, 2022
Note: This article was written a while ago and may contain outdated information. Please verify the details before relying on it. If I express opinions or recommendations, they might not reflect my current views. For this reason, I recommend checking for more recent articles on the same topic.

Mockito is a really powerful tool. And even more: It’s documentation and logs are so good, that you don’t need to look at the documentation if you’re misusing it! Here I’ll show some of the common functions I’m using with a small example.

Example application

I’ll show you an example application, which I’ll use within the next sections. The example may not to seem so logical, but it will show you the most important things.

Let’s imagine the following interface:

public interface VehicleIF {
    void move(Speed speedName);
}

And the following enum:

public enum Speed {
    FAST,
    MEDIUM,
    SLOW
}

This is implemented by the Train and Bike (I’m using here some Spring Boot annotations, but this should also work in other Frameworks / plain Java):

@Component
public class Train implements VehicleIF {
    @Override
    public void move(Speed speedName) {
        // do Train specific things
    }
}
@Component
public class Bike implements VehicleIF {
    @Override
    public void move(Speed speedName) {
        // Do Bike specific things
    }
}

Based on the day we want to use either the Bike or Train. So on weekdays we use the bike and on saturday the train. On sunday we do nothing. The DriverComponent implements the logic for us:

@Component
public class DriverComponent {
    @Autowired
    Bike bike;

    @Autowired
    Train train;

    public void execute() {
        boolean isSaturday = LocalDateTime.now().getDayOfWeek().equals(DayOfWeek.SATURDAY);
        boolean isSunday = LocalDateTime.now().getDayOfWeek().equals(DayOfWeek.SUNDAY);

        if (isSunday) {
            return;
        }

        if (isSaturday) {
            train.move(Speed.FAST);
            return;
        }

        bike.move(Speed.MEDIUM);
    }
}

You also see here the speed of our movement.

Now, let’s test it!

Testing with Mockito and JUnit

The final implementation will look like the following one, using most common mock methods. Head over if you want to read what every line does:

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.*;
import org.mockito.junit.jupiter.MockitoExtension;

import java.time.DayOfWeek;
import java.time.LocalDateTime;

@ExtendWith(MockitoExtension.class)
public class DriverComponentTest {
    MockedStatic<LocalDateTime> localDateTimeMocked;

    @Mock
    Train train;

    @Mock
    Bike bike;

    @InjectMocks
    DriverComponent driverComponent;

    @AfterEach
    void tearDown() {
        localDateTimeMocked.closeOnDemand();
    }

    @Test
    public void executesTrainOnSaturday() {
        localDateTimeMocked = Mockito.mockStatic(LocalDateTime.class, Mockito.CALLS_REAL_METHODS);
        LocalDateTime now = LocalDateTime.of(2022, 10, 22, 10, 0);
        localDateTimeMocked.when(LocalDateTime::now).thenReturn(now);

        driverComponent.execute();

        Mockito.verifyNoInteractions(bike);
        ArgumentCaptor<Speed> speedCaptor = ArgumentCaptor.forClass(Speed.class);
        Mockito.verify(train, Mockito.times(1))
                .move(speedCaptor.capture());

        Assertions.assertEquals(speedCaptor.getValue(), Speed.FAST);
    }
}

Creation of the test class

Let’s assume that we want to test, that the execution on saturday is correct.

First, create the test class with it’s method and annotate it with @ExtendWith(MockitoExtension.class):

@ExtendWith(MockitoExtension.class)
public class DriverComponentTest {

    @Test
    public void executesTrainOnSaturday() {
    }
}

Mock statics with Mockito

In our test, we want to test the behavior on Saturdays. So let’s make it saturday. In the past Mockito didn’t allow to mock statics and you need to use other libraries for this. But, the feature to mock statics is not in the core and in the mockito-inline library, which is a feedback path for Mockito developers before they move new features into the core. So you need to add it to your build.gradle:

testImplementation 'org.mockito:mockito-inline:4.8.0'

Otherwise you’ll get the following message:

Mockito’s inline mock maker supports static mocks based on the Instrumentation API. You can simply enable this mock mode, by placing the ‘mockito-inline’ artifact where you are currently using ‘mockito-core’.

To mock statics, you need to use the MockedStatic container on the class you want to mock:

    MockedStatic<LocalDateTime> localDateTimeMocked;

Static mocks are open per thread. So you need to close the mock after it’s usage, as otherwise the static mock will be kept opened on the thread:

@AfterEach 
void tearDown() {
    localDateTimeMocked.closeOnDemand();
}

In the test method we can create an instance of the static mock:

localDateTimeMocked = Mockito.mockStatic(LocalDateTime.class, Mockito.CALLS_REAL_METHODS);

In this case Mockito.CALLS_REAL_METHODS means that in any case the Mock fails, it should use the real method.

Now define the date which shall be returned when calling the LocalDateTime::now function.

        LocalDateTime now = LocalDateTime.of(2022, 10, 22, 10, 0);
        localDateTimeMocked.when(LocalDateTime::now).thenReturn(now);

Now the test class looks like this:

@ExtendWith(MockitoExtension.class)
public class DriverComponentTest {

    MockedStatic<LocalDateTime> localDateTimeMocked;

    @AfterEach
    void tearDown() {
        localDateTimeMocked.closeOnDemand();
    }

    @Test
    public void executesTrainOnSaturday() {
        localDateTimeMocked = Mockito.mockStatic(LocalDateTime.class, Mockito.CALLS_REAL_METHODS);
        LocalDateTime now = LocalDateTime.of(2022, 10, 22, 10, 0);
        localDateTimeMocked.when(LocalDateTime::now).thenReturn(now);
    }
}

Execute the component

Now we have prepared everything for the execution of the component. So let’s do it in the test method:

driverComponent.execute();

Oh! The driverComponent needs to be accessible. And as the behavior of it’s inner components Train and Bike needs to be checked, they will also be marked as @Mock. This fields need to be added:

@Mock
Train train;

@Mock
Bike bike;

@InjectMocks
DriverComponent driverComponent;

Verify the behavior

The expected behaviour is:

No interactions with Bike and the move method of Train gets executed one time with an argument of the type Speed.class.

This can be done in Mockito with this lines:

Mockito.verifyNoInteractions(bike);
Mockito.verify(train, Mockito.times(1))
    .move(ArgumentMatchers.any(Speed.class));

With Mockito.times(1) you assure that the method was invoked exactly once.

The ArgumentMatchers assure that arguments are passed. You can use types as they are needed. Or if you don’t care, then you can also use ArgumentMatchers.any().

Verify the value of an argument

But it is also possible to use Mockito to assure the value of a passed argument. This gives you more power in your tests.

For this ArgumentCaptors are used.

First, define the captor for the class:

ArgumentCaptor<Speed> speedCaptor = ArgumentCaptor.forClass(Speed.class);

In the mocked train use the captor to capture the passed arguments with speedCaptor.capture():

Mockito.verify(train, Mockito.times(1))
    .move(speedCaptor.capture());

And finally assure that the value was Speed.FAST as expected:

Assertions.assertEquals(speedCaptor.getValue(), Speed.FAST);

Keep the order

Keep in mind, that you first need to execute your method before you start to use the verify methods of Mockito. Otherwise your assertions won’t work.

Other features

What this example didn’t covered was the return of values, which can be helpful in many cases.

For example assume that you have a repository with one method findById(int id):

public class BookRepository {
    Book findById(int id) {
        // access the database and return the Book instance
    }
}

You can @Mock this class and inject it into the component you want to test (via @InjectMocks). Now you can make your component work with the data you need.

For this use the thenReturn methods:

Mockito.when(bookRepository.findById(ArgumentMatchers.anyInt()))
        .thenReturn(new Book(...));

It is also possible to add methods to it and build a whole mocked database, if you want to. But that makes things really complicated and you should use Testcontainers or a temporary database like H2 for this.

Further look

This was just a small insight into the awesome and powerful Mockito framework.

Mockito has many other interesting features like the @Spy annotation and it’s methods, which will not be covered here. Look into the documentation if you want to test something and the methods mentioned above don’t fit.

Keep in mind that there are always other test methods which may also fit good into your use case.

Full code on GitHub.