Home Tutorials Training Consulting Books Company Contact us


Get more...

This tutorial explains the usage of the Mockito framework for writing software tests with JUnit 5 in Java.

1. Prerequisites

This tutorial introduces the usage of Mockito for JUnit tests. If you are not familiar with JUnit, please read first the JUnit Tutorial.

2. Using Mockito for mocking objects in unit tests

Mockito is a popular open source framework for mocking objects in software test. Using Mockito greatly simplifies the development of tests for classes with external dependencies.

A mock object is a dummy implementation for an interface or a class. It allows to define the output of certain method calls. They typically record the interaction with the system and tests can validate that.

This allows you to simplify the test setup.

mockitousagevisualization

Recent versions of Mockito can also mock static methods and final classes. See Mockito limitations for an overview of the remaining limitations. Also private methods are not visible for tests, they can also not be mocked. See private methods for details.

Mockito records the interaction with mock and allows you to check if the mock object was used correct, e.g. if a certain method has been called on the mock. This allows you to implement behavior testing instead of only testing the result of method calls.

// state testing
testSort() {
    testList = [1, 7, 3, 8, 2]
    MySorter.sort(testList)

    assert testList equals [1, 2, 3, 7, 8]
}


// incorrect would be behavior testing
// the following tests internal of the implementation
testSort() {
    testList = [1, 7, 3, 8, 2]
    MySorter.sort(testList)

    assert that compare(1, 2) was called once
    assert that compare(1, 3) was not called
    assert that compare(2, 3) was called once
    ....
}

For further information about testing with Java see:

3. Adding Mockito to a project

Using the Mockito libraries should be done with a modern dependency system like Maven or Gradle. All modern IDEs (Eclipse, Visual Studio Code, IntelliJ) support both Maven and Gradle.

The following contains detailed descriptions for your environment, pick the one which is relevant for you. The latest version of Mockito can be found via https://search.maven.org/artifact/org.mockito/mockito-core.

Using Maven

To use Mockito in your Maven project, add the following dependency to your pom file. It assumes that you already added the dependencies for your test framework, e.g. JUnit 5.

<!-- https://mvnrepository.com/artifact/org.mockito/mockito-core -->
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>{mockitoversion}</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-junit-jupiter</artifactId>
    <version>{mockitoversion}</version>
    <scope>test</scope>
</dependency>

Use the latest version from https://mvnrepository.com/artifact/org.mockito/mockito-core instead of 5.14.2.

mockito-junit-jupiter` adds the MockitoExtension for JUnit 5.
Using Gradle for a Java project

To use Mockito in a Gradle project, add the following dependency to the build.gradle file. It assumes that you already added the dependencies for your test framework, e.g. JUnit 5.

dependencies {
    testImplementation 'org.mockito:mockito-core:{mockitoversion}'
    testImplementation 'org.mockito:mockito-junit-jupiter:{mockitoversion}'
    }
Using Mockito for an Android project

Add the following dependency to the Gradle build file:

dependencies {
    // ... more entries
    // required if you want to use Mockito for unit tests
    testCompile 'org.mockito:mockito-core:{mockitoversion}'
    // required if you want to use Mockito for Android tests
    androidTestCompile 'org.mockito:mockito-android:{mockitoversion}'
}
OSGi or Eclipse plug-in development

In OSGi or Eclipse plug-in/ RCP development you can use Maven dependencies via your target platform. See Using Java libraries for Eclipse / OSGi development tutorial.

4. Creating mock objects with the Mockito API

Mockito provides several methods to create mock objects:

  • Using the @ExtendWith(MockitoExtension.class) extension for JUnit 5 in combination with the @Mock annotation on fields

  • Using the static mock() method.

  • Using the @Mock annotation.

If you use the @Mock annotation, you must trigger the initialization of the annotated fields. The MockitoExtension does this by calling the static method MockitoAnnotations.initMocks(this).

For example, consider the following data model.

package com.vogella.junit5;

public class Database {

    public boolean isAvailable() {
        // currently not implemented, as this is just demo used in a software test
        return false;
    }
    public int getUniqueId() {
        return 42;
    }
}
package com.vogella.junit5;

public class Service {

    private Database database;

    public Service(Database database) {
        this.database = database;
    }

    public boolean query(String query) {
        return database.isAvailable();
    }


    @Override
    public String toString() {
        return "Using database with id: " + String.valueOf(database.getUniqueId());
    }
}

A unit test using Mockito which mocks the Database object could look like the following.

package com.vogella.junit5;

import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.when;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)                         (1)
class ServiceTest {

    @Mock
    Database databaseMock;                                  (2)

    @Test
    public void testQuery()  {
        assertNotNull(databaseMock);
        when(databaseMock.isAvailable()).thenReturn(true);  (3)
        Service t  = new Service(databaseMock);             (4)
        boolean check = t.query("* from t");                (5)
        assertTrue(check);
    }
}
1 Tells Mockito to create the mocks based on the @Mock annotation, this requires JUnit 5, if you an oder version of JUnit, call Mock.init() in your setup method
2 Tells Mockito to mock the databaseMock instance
3 Configure the Mock to return true when its isAvailable method is called, see later for more options
4 Executes some code of the class under test
5 Asserts that the method call returned true
Static imports

Mockito provides a lot of static methods for mock and asserts. By adding the org.mockito.Mockito.*; static import, you can use these methods directly in your tests. Static imports allow you to call static members, i.e., methods and fields of a class directly without specifying the class.

Using static imports also greatly improves the readability of your test code.

5. Configuring the return values of methods calls on the mock objects

Mockito allows to configure the return values of methods which are called on the mock via a fluent API. Unspecified method calls return "empty" values:

  • null for objects

  • 0 for numbers

  • false for boolean

  • empty collections for collections

  • …​

The following assert statements are only for demonstration purposes, a real test would use the mocks to unit test another functionality.

5.1. Using when().thenReturn() and when().thenThrow()

Mocks can return different values depending on arguments passed into a method. The when(…​.).thenReturn(…​.) method chain is used to specify a return value for a method call with pre-defined parameters.

whenThenReturn10

You also can use methods like anyString or anyInt to define that dependent on the input type a certain value should be returned.

If you specify more than one value, they are returned in the order of specification, until the last one is used. Afterwards the last specified value is returned.

The following demonstrates the usage of when(…​.).thenReturn(…​.).

package com.vogella.junit5;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class) 
class ServiceDatabaseIdTest {

    @Mock
    Database databaseMock;

    @Test
    void ensureMockitoReturnsTheConfiguredValue() {

        // define return value for method getUniqueId()
        when(databaseMock.getUniqueId()).thenReturn(42);

        Service service = new Service(databaseMock);
        // use mock in test....
        assertEquals(service.toString(), "Using database with id: 42");
    }

}

Other examples which demonstrates the configuration of Mockito are in the following listing. These are not real test, the test only validating the Mockito configuration.

package com.vogella.junit5;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.Mockito.when;

import java.util.Iterator;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;


@ExtendWith(MockitoExtension.class)
class MockitoWhenExampleTest {
    
    @Mock
    Iterator<String> i;
    
    Comparable<String> c;

    // demonstrates the return of multiple values
    @Test
    void testMoreThanOneReturnValue() {
        when(i.next()).thenReturn("Mockito").thenReturn("rocks");
        String result = i.next() + " " + i.next();
        // assert
        assertEquals("Mockito rocks", result);
    }

    // this test demonstrates how to return values based on the input
    // and that @Mock can also be used for a method parameter
    @Test
    void testReturnValueDependentOnMethodParameter(@Mock Comparable<String> c)  {
            when(c.compareTo("Mockito")).thenReturn(1);
            when(c.compareTo("Eclipse")).thenReturn(2);
            //assert
            assertEquals(1, c.compareTo("Mockito"));
            assertEquals(2, c.compareTo("Eclipse"));
    }
    
    // return a value based on the type of the provide parameter

    @Test
    void testReturnValueInDependentOnMethodParameter2(@Mock Comparable<Integer> c )  {
            when(c.compareTo(isA(Integer.class))).thenReturn(0);
            //assert
            assertEquals(0, c.compareTo(Integer.valueOf(4)));
    }

}

The when(…​.).thenReturn(…​.) method chain can be used to throw an exception.

package com.vogella.junit5;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.when;

import java.util.Properties;

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


class MockitoThrowsTest {
    
    // demonstrates the configuration of a throws with Mockito
    // not a read test, just "testing" Mockito behavior
    @Test
    void testMockitoThrows() {
        Properties properties = Mockito.mock(Properties.class);

        when(properties.get(Mockito.anyString())).thenThrow(new IllegalArgumentException("Stuff"));

        Throwable exception = assertThrows(IllegalArgumentException.class, () -> properties.get("A"));

        assertEquals("Stuff", exception.getMessage());
    }
}

5.2. doReturn when and doThrow when

The doReturn(…​).when(…​) method configuration can be used to configure the reply of a mocked method call. This is similar to when(…​.).thenReturn(…​.).

As when(…​.).thenReturn(…​.) is easier to read, you should prefer using it. But doReturn can be useful if you are using spies, e.g. with @Spy, in Mockito. In case of a spy Mockito uses the underlying object and when(…​.).thenReturn(…​.) will call the underlying method which may create side effects. If these side effects are not desired, use doReturn, e.g. if you spy on a list and a certain operation would result in an undesired exception from the original object, like requesting the element in position 2 of an empty list.

package com.vogella.junit5;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;

import java.util.Properties;

import org.junit.jupiter.api.Test;


class MockitoSpyWithListTest {
    
    // demonstrates of the spy function
    @Test
    void ensureSpyForListWorks() {
        var list = new ArrayList<String>();
        var spiedList = spy(list);

        doReturn("42").when(spiedList).get(99);
        String value = (String) spiedList.get(99);

        assertEquals("42", value);
    }
}

The doThrow variant can be used for methods which return void to throw an exception. This usage is demonstrated by the following code snippet.

package com.vogella.junit5;

import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;

import org.junit.jupiter.api.Test;


class MockitoThrowsTest {
    
    @Test
    public void testForIOException() throws IOException {
        // create an configure mock
        OutputStream mockStream = mock(OutputStream.class);
        doThrow(new IOException()).when(mockStream).close();

        // use mock
        OutputStreamWriter streamWriter = new OutputStreamWriter(mockStream);

        assertThrows(IOException.class, () -> streamWriter.close());
    }


}

6. Wrapping Java objects with Spy

@Spy or the spy() method can be used to wrap a real object. Every call, unless specified otherwise, is delegated to the object.

package com.vogella.mockito.spy;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.doReturn;

import java.util.LinkedList;
import java.util.List;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
class MockitoSpyTest {

    @Spy
    List<String> spy = new LinkedList<>();

    @BeforeEach
    void setup() {
        // Alternative way of creating a spy
        // List<String> list = new LinkedList<>();
        // List<String> spy = spy(list);
    }

    @Test
    void testLinkedListSpyCorrect() {

        // when(spy.get(0)).thenReturn("foo");
        // would not work as the delegate it called so spy.get(0)
        // throws IndexOutOfBoundsException (list is still empty)

        // you have to use doReturn() for stubbing
        doReturn("foo").when(spy).get(0);

        assertEquals("foo", spy.get(0));
    }

}

6.1. Verify the calls on the mock objects

Mockito keeps track of all the method calls and their parameters to the mock object. You can use the verify() method on the mock object to verify that the specified conditions are met. For example, you can verify that a method has been called with certain parameters. This kind of testing is sometimes called behavior testing. Behavior testing does not check the result of a method call, but it checks that a method is called with the right parameters.

package com.vogella.junit5;

import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentMatchers;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class) 
public class MockitoVerifyTest {


    @Test
    public void testVerify(@Mock Database database)  {
        // create and configure mock
        when(database.getUniqueId()).thenReturn(43);
        
        
        // call method testing on the mock with parameter 12
        database.setUniqueId(12);
        database.getUniqueId();
        database.getUniqueId();
        
        
        // now check if method testing was called with the parameter 12 
        verify(database).setUniqueId(ArgumentMatchers.eq(12));
        
        // was the method called twice?
        verify(database, times(2)).getUniqueId();
        
        // other alternatives for verifiying the number of method calls for a method
        verify(database, never()).isAvailable();
        verify(database, never()).setUniqueId(13);
        verify(database, atLeastOnce()).setUniqueId(12);
        verify(database, atLeast(2)).getUniqueId();
        
        // more options are 
        // times(numberOfTimes)
        // atMost(numberOfTimes)
        // This let's you check that no other methods where called on this object.
        // You call it after you have verified the expected method calls.
        verifyNoMoreInteractions(database);
    }

}

In case you do not care about the value, use the anyX, e.g., anyInt, anyString(), or any(YourClass.class) methods.

7. Using @InjectMocks for dependency injection via Mockito

You also have the @InjectMocks annotation which tries to do constructor, method or field dependency injection of mock objects in to other type. It does not require @Inject to be present and also does not try to be a full features dependency injection framework but is helpful to wire up objects to be tested.

For example, assume you have a class named ArticleManager with the following constructor:

public ArticleManager(User user, ArticleDatabase database) {
 // more code...
}

This class can be constructed via Mockito. The parameters to the constructor could be supplied via mock objects as demonstrated by the following code snippet.

package com.vogella.junit5;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class) 
class ArticleManagerTest {

    @Mock 
    ArticleDatabase database;
    
    @Mock 
    User user;
    
    @InjectMocks 
    private ArticleManager manager; (1)

    @Test 
    void shouldDoSomething() {
       // TODO perform some tests with this managers
    }
}
1 creates an instance of ArticleManager and injects the mocks into it

You find a full example of the usage of @InjectMocks in the exercises. Mockito can inject mocks either via constructor injection, setter injection, or property injection and in this order. So if ArticleManager would have a constructor that would only take User and setters for both fields, only the mock for User would be injected.

8. Capturing the arguments

The ArgumentCaptor class allows to access the arguments of method calls during the verification. This allows to capture these arguments of method calls and to use them for tests.

To run this example you need to add hamcrest-library to your project.

package com.vogella.junit5;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItem;
import static org.mockito.Mockito.verify;

import java.util.Arrays;
import java.util.List;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
public class MockitoArgumentCaptureTest {

    @Captor
    private ArgumentCaptor<List<String>> captor;

    @Test
    public final void shouldContainCertainListItem(@Mock List<String> mockedList) {
        var asList = Arrays.asList("someElement_test", "someElement");
        mockedList.addAll(asList);

        verify(mockedList).addAll(captor.capture());
        List<String> capturedArgument = captor.getValue();
        assertThat(capturedArgument, hasItem("someElement"));
    }
}

9. Using Answers for complex mocks

thenReturn returns a predefined value every time. With an Answer object you can calculate a response based on the arguments given to your stubbed method.

This can be useful if your stubbed method is supposed to call a function on one of the arguments or if your method is supposed to return the first argument to allow method chaining. There exists a static method for the latter. Also note that there a different ways to configure an answer:

import static org.mockito.AdditionalAnswers.returnsFirstArg;

@Test
public final void answerTest() {
    // with doAnswer():
    doAnswer(returnsFirstArg()).when(list).add(anyString());
    // with thenAnswer():
    when(list.add(anyString())).thenAnswer(returnsFirstArg());
    // with then() alias:
    when(list.add(anyString())).then(returnsFirstArg());
}

Or if you need to do a callback on your argument:

@Test
public final void callbackTest() {
    ApiService service = mock(ApiService.class);
    when(service.login(any(Callback.class))).thenAnswer(i -> {
        Callback callback = i.getArgument(0);
        callback.notify("Success");
        return null;
    });
}

It is even possible to mock a persistence service like an DAO, but you should consider creating a fake class instead of a mock if your Answers become too complex.

List<User> userMap = new ArrayList<>();
UserDao dao = mock(UserDao.class);
when(dao.save(any(User.class))).thenAnswer(i -> {
    User user = i.getArgument(0);
    userMap.add(user.getId(), user);
    return null;
});
when(dao.find(any(Integer.class))).thenAnswer(i -> {
    int id = i.getArgument(0);
    return userMap.get(id);
});

10. More on Mockito

10.1. Mocking final classes and static methods

With recent versions of Mockito it is possible to mock final classes and static methods. For example, if you have the following final class:

final class FinalClass {
    public final String finalMethod() { return "something"; }
}

You can mock it via the following code:

package com.vogella.junit5;

import static org.junit.jupiter.api.Assertions.assertNotNull;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
public class MockitoMockFinal {


    @Test
    public void testMockFinal(@Mock FinalClass finalMocked)  {
        assertNotNull(finalMocked);
    }

    @Test
    public void testMockFinalViaMockStatic()  {
        MockedStatic<FinalClass> mockStatic = Mockito.mockStatic(FinalClass.class);
        assertNotNull(mockStatic);
    }
}

Mockito also allows to mock static methods.

package com.vogella.junit5;

public class Utility {

    public static String getDatabaseConnection(String url) {
        return "http:///production/" + url;
    }
}
package com.vogella.junit5;

import static org.junit.jupiter.api.Assertions.assertEquals;

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

class MyUtilsTest {

    @Test
    void shouldMockStaticMethod() {
        MockedStatic<FinalClass> mockStatic = Mockito.mockStatic(FinalClass.class);
        try (MockedStatic<Utility> mockedStatic = Mockito.mockStatic(Utility.class)) {

            mockedStatic.when(() -> Utility.getDatabaseConnection(Mockito.eq("test"))).thenReturn("testing");
            mockedStatic.when(() -> Utility.getDatabaseConnection(Mockito.eq("prod"))).thenReturn("production");

            String result1 = Utility.getDatabaseConnection("test");

            assertEquals("testing", result1);
            String result2 = Utility.getDatabaseConnection("prod");
            assertEquals("production", result2);

        }

    }
}

10.2. Clean test code with the help of the strict stubs rule

The strict stubs rule helps you to keep your test code clean and checks for common oversights. It adds the following:

  • test fails early when a stubbed method gets called with different arguments than what it was configured for (with PotentialStubbingProblem exception).

  • test fails when a stubbed method isn’t called (with UnnecessaryStubbingException exception).

  • org.mockito.Mockito.verifyNoMoreInteractions(Object) also verifies that all stubbed methods have been called during the test

@Test
public void withoutStrictStubsTest() throws Exception {
    DeepThought deepThought = mock(DeepThought.class);

    when(deepThought.getAnswerFor("Ultimate Question of Life, The Universe, and Everything")).thenReturn(42);
    when(deepThought.otherMethod("some mundane thing")).thenReturn(null);

    System.out.println(deepThought.getAnswerFor("Six by nine"));

    assertEquals(42, deepThought.getAnswerFor("Ultimate Question of Life, The Universe, and Everything"));
    verify(deepThought, times(1)).getAnswerFor("Ultimate Question of Life, The Universe, and Everything");
}
// activate the strict subs rule
@Rule public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);

@Test
public void withStrictStubsTest() throws Exception {
    DeepThought deepThought = mock(DeepThought.class);

    when(deepThought.getAnswerFor("Ultimate Question of Life, The Universe, and Everything")).thenReturn(42);
    // this fails now with an UnnecessaryStubbingException since it is never called in the test
    when(deepThought.otherMethod("some mundane thing")).thenReturn(null);

    // this will now throw a PotentialStubbingProblem Exception since we usually don't want to call methods on mocks without configured behavior
    deepThought.someMethod();

    assertEquals(42, deepThought.getAnswerFor("Ultimate Question of Life, The Universe, and Everything"));
    // verifyNoMoreInteractions now automatically verifies that all stubbed methods have been called as well
    verifyNoMoreInteractions(deepThought);
}

11. Exercise: Create a new Maven or Gradle project with Mockito support

Create a new Maven or Gradle project named com.vogella.mockito.

Add the required libraries to your project depending on your build system.

Using Maven to add Mockito to your project

To use Mockito in your Maven project, add the following dependency to your pom file. It assumes that you already added the dependencies for your test framework, e.g. JUnit 5.

<!-- https://mvnrepository.com/artifact/org.mockito/mockito-core -->
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>{mockitoversion}</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-junit-jupiter</artifactId>
    <version>{mockitoversion}</version>
    <scope>test</scope>
</dependency>

Use the latest version from https://mvnrepository.com/artifact/org.mockito/mockito-core instead of 5.14.2.

mockito-junit-jupiter` adds the MockitoExtension for JUnit 5.
Using Gradle to add Mockito to your project

To use Mockito in a Gradle project, add the following dependency to the build.gradle file. It assumes that you already added the dependencies for your test framework, e.g. JUnit 5.

dependencies {
    testImplementation 'org.mockito:mockito-core:{mockitoversion}'
    testImplementation 'org.mockito:mockito-junit-jupiter:{mockitoversion}'
    }

You can now use Mockito in your project.

12. Exercise: Testing an API with Mockito and JUnit 5

12.1. Create an AudioManager API

Create the following classes which will be used in the following tests.

package com.vogella.mockito.audio;

public enum RINGER_MODE {
    RINGER_MODE_NORMAL, RINGER_MODE_SILENT
}
package com.vogella.mockito.audio;

public class AudioManager {
    private int volume = 50;
    private RINGER_MODE mode = RINGER_MODE.RINGER_MODE_SILENT;
    
    public RINGER_MODE getRingerMode() {
        return mode;
    }
    public int getStreamMaxVolume() {
        return volume;
    }
    public void setStreamVolume(int max) {
        volume = max;
    }
    public void makeReallyLoad() {
        if (mode.equals(RINGER_MODE.RINGER_MODE_NORMAL)) {
            setStreamVolume(100);
        }
    }
    
}
package com.vogella.mockito.audio;

public class MyApplication {

    public int getNumberOfThreads() {
        return 5;
    }

}
package com.vogella.mockito.audio;

public class ConfigureThreadingUtil {
    public static void configureThreadPool(MyApplication app){
        int numberOfThreads = app.getNumberOfThreads();
        // TODO use information to configure the thread pool


    }
}
package com.vogella.mockito.audio;

public class VolumeUtil {
    public static void maximizeVolume(AudioManager audioManager) {
        if (audioManager.getRingerMode() != RINGER_MODE.RINGER_MODE_SILENT) {
            int max = audioManager.getStreamMaxVolume();
            audioManager.setStreamVolume(max);
        }
        audioManager.setStreamVolume(50);
    }
}

12.2. Testing VolumeUtil

We want to test VolumeUtil using Mockito.

package com.vogella.mockito.audio;


import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;

import org.junit.jupiter.api.Test;

class VolumeUtilTests {
    @Test
    void testNormalRingerIsMaximized(){
        // 1.) Ensure AudioManager gets mocked
        // 2.) configure Audiomanager to return RINGER_MODE_NORMAL if getRinderMode is called
        // 3.) configure Audiomanager to return 100 if getStreamMaxVolume() is called
        // 4.) call VolumeUtil.maximizeVolume with Audiomanager -> code under test
        // 5.) verify that setStreamVolume(100) was called on audioManager

    }

    @Test
    void testSilentRingerIsNotDisturbed() {
        // 1.) Ensure AudioManager gets mocked
        // 2.) configure audiomanager to return "RINGER_MODE_SILENT" if getRingerMode is called
        // 3.) call VolumeUtil.maximizeVolume with audio manager
        // 4.) verify that getRingerMode() is called on the mock
        // 5.) Ensure that nothing more was called


    }
}
Solution
package com.vogella.mockito.audio;


import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;

import org.junit.jupiter.api.Test;

@ExtendWith(MockitoExtension.class)
class VolumeUtilTests {
    
    @Mock
    AudioManager audioManager;

    
    @Test
    void ensureThatMaximizeVolumeUseConfiguredValueFromAudiomanager() {
      // 1. script mock behavior.
      when(audioManager.getRingerMode()).thenReturn(RINGER_MODE.RINGER_MODE_NORMAL);
      when(audioManager.getStreamMaxVolume()).thenReturn(100);

      // 2. Test the code of interest.
      
      VolumeUtil.maximizeVolume(audioManager);

      // 3. Validate that we saw exactly what we wanted.
      verify(audioManager).setStreamVolume(100);
    }

    @Test
    void ensureSilentModeWillNotSetVolumeIsNotDisturbed() {
         // 1. script mock behavior.
          AudioManager audioManager = mock(AudioManager.class);
          when(audioManager.getRingerMode()).thenReturn(RINGER_MODE.RINGER_MODE_SILENT);
          // 2. Test the code of interest.
          VolumeUtil.maximizeVolume(audioManager);
          // 3. Validate that we saw exactly what we wanted.
          verify(audioManager).getRingerMode();
          verifyNoMoreInteractions(audioManager);
    }
}

The second test should find an error in VolumeUtil. Fix this in the original code.

Solution
package com.vogella.mockito.audio;

public class VolumeUtil {
    public static void maximizeVolume(AudioManager audioManager) {
        if (audioManager.getRingerMode() != RINGER_MODE.RINGER_MODE_SILENT) {
            int max = audioManager.getStreamMaxVolume();
            audioManager.setStreamVolume(max);
        }
    }
}

12.3. Write a new Mockito test for ConfigureThreadingUtil

Write a new test which implements the following test comments using the following template.

package com.vogella.mockito.audio;

import org.junit.jupiter.api.Test;

class ConfigureThreadingUtilTests {
    @Test
    void ensureThatThreadPoolCanBeConfigured() {
        // mock MyApplication
        // call ConfigureThreadingUtil.configureThreadPool
        // verify that getNumberOfThreads was the only one called on app
    }
}
Solution
package com.vogella.mockito.audio;

import static org.mockito.Mockito.only;
import static org.mockito.Mockito.verify;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
class ConfigureThreadingUtilTests {

    @Mock
    MyApplication app;

    @Test
    void ensureThatThreadPoolCanBeConfigured() {
        // mock MyApplication
        ConfigureThreadingUtil.configureThreadPool(app);
        verify(app, only()).getNumberOfThreads();
    }
}

13. Exercise: Using @Spy from Mockito

Write a test named TestingSpy. Configure a List<String> with the @Spy annotation to return a certain string for the get(10000000) on on the list.

HINT: Use doReturn to configure the spy

Show Solution
package com.vogella.mockito.spy;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.doReturn;

import java.util.LinkedList;
import java.util.List;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
class TestingSpy {

    @Spy
    List<String> list = new LinkedList<>();

    @Test
    void ensureToLearnAboutSpy() {

        int highNumber = 10000000;
        doReturn("Big list").when(list).get(highNumber);
        assertEquals("Big list", list.get(highNumber));
    }
}

14. Exercise: Using @InjectMock

In this exercise you use @InjectMock to get your mocks injected into another mock.

14.1. Create a simple data model

Create for this example the following classes.

package com.vogella.mockito.inject;

public class User {
    String name;

    public User(String name) {
        this.name = name;
    }
}
package com.vogella.mockito.inject;

public class ArticleListener {

}
package com.vogella.mockito.inject;

public class ArticleDatabase {

    private ArticleListener articleListener;
    private User user;

    public void addListener(ArticleListener articleListener) {
        this.articleListener = articleListener;
    }

    public void setUser(User user) {
        this.user = user;
    }

}
package com.vogella.mockito.inject;

import java.util.Objects;

public class ArticleManager {
    private User user;
    private ArticleDatabase database;

    // not necessary for Mockito but a Java standard supported by many framework
    // would be the usage of @Inject from Java Specification Request (JSR 330)
    // @Inject
    public ArticleManager(User user, ArticleDatabase database) {
        Objects.requireNonNull(user);
        Objects.requireNonNull(database);
        this.user = user;
        this.database = database;
    }

    public void initialize() {
        database.addListener(new ArticleListener());
        database.setUser(user);
    }
}

14.2. Create a test

Create a new test named ArticleManagerTest uses

package com.vogella.mockito.inject;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
class ArticleManagerTest {

    //
    @InjectMocks
    private ArticleManager manager;

    @Test
    void ensureInjectMockWorks() {
        // calls addListener with an instance of ArticleListener
        manager.initialize();
        // TODO verify that addListener was called with any (instance) of ArticleListener.class
        // TODO
    }
}

If you run this test, you get an error.

org.mockito.exceptions.misusing.InjectMocksException:
Cannot instantiate @InjectMocks field named 'manager' of type 'class com.vogella.mockito.inject.ArticleManager'.
You haven't provided the instance at field declaration so I tried to construct the instance.
However the constructor or the initialization block threw an exception : null

Fix this by providing the required mocks. Also implement the TODOs.

14.3. Solution

Solution
package com.vogella.mockito.inject;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
class ArticleManagerTest {

    @Mock
    ArticleDatabase database;

    @Mock
    User user;

    @InjectMocks
    private ArticleManager manager;

    @Test
    void ensureInjectMockWorks() {
        // calls addListener with an instance of ArticleListener
        manager.initialize();

        // validate that addListener was called
        verify(database).addListener(any(ArticleListener.class));
        verify(database).setUser(user);
    }
}

15. Exercise: Mocking final classes and static methods

Recent releases of Mockito can also mock final classes and static methods. For final classes and final methods Mockito just works, for static methods you have to use the mockStatic method.

package com.vogella.mockito.mockstatic;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.anyString;

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

class MyStaticDemoTest {

    @Test
    void testStaticMockVoid() {
        try (MockedStatic<Dummy> dummy = Mockito.mockStatic(Dummy.class)) {
            dummy.when(Dummy::foo).thenReturn("mocked");
            dummy.when(() -> Dummy.foo(anyString())).thenReturn("mockedValue");

            assertEquals("mocked", Dummy.foo());
            assertEquals("mockedValue", Dummy.foo("para"));
            dummy.verify(() -> Dummy.foo());
            dummy.verify(() -> Dummy.foo(anyString()));
        }
    }

    static final class Dummy {
        public int testing() {
            return var1.length();
        }

        static String var1 = null;

        static String foo() {
            return "foo";
        }

        static String foo(String var2) {
            var1 = var2;
            return "SUCCESS";
        }
    }
}

15.1. Creating a bigger example static mock test

In this exercise, you create a test using to for this copied from the Mockito tests and migrated to JUnit5.

Create the following test and review it to see that is possible with static mocking in Mockito.

/*
 * Copyright (c) 2020 Mockito contributors
 * This program is made available under the terms of the MIT License.
 */
package com.vogella.mockito.mockstatic;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.times;

import java.util.concurrent.atomic.AtomicReference;

import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.mockito.exceptions.base.MockitoException;
import org.mockito.exceptions.verification.NoInteractionsWanted;
import org.mockito.exceptions.verification.WantedButNotInvoked;

class StaticMockTest {

    @Test
    void testStaticMockSimple() {
        assertEquals("foo", Dummy.foo());
        try (MockedStatic<Dummy> ignored = mockStatic(Dummy.class)) {
            assertNull(Dummy.foo());
        }
        assertEquals("foo", Dummy.foo());
    }

    @Test
    void testStaticMockWithVerification() {
        try (MockedStatic<Dummy> dummy = mockStatic(Dummy.class)) {
            dummy.when(Dummy::foo).thenReturn("bar");
            assertEquals("bar", Dummy.foo());
            dummy.verify(Dummy::foo);
        }
    }

    void testStaticMockWithVerificationFailed() {
        try (MockedStatic<Dummy> dummy = mockStatic(Dummy.class)) {

            assertThrows(WantedButNotInvoked.class, () -> {
                dummy.verify(Dummy::foo);
            });
        }
    }

    @Test
    void testStaticMockWithMoInteractions() {
        try (MockedStatic<Dummy> dummy = mockStatic(Dummy.class)) {
            dummy.when(Dummy::foo).thenReturn("bar");
            dummy.verifyNoInteractions();
        }
    }

    void testStaticMockWithMoInteractionsFailed() {
        try (MockedStatic<Dummy> dummy = mockStatic(Dummy.class)) {
            dummy.when(Dummy::foo).thenReturn("bar");
            assertEquals("bar", Dummy.foo());

            assertThrows(NoInteractionsWanted.class, () -> {
                dummy.verifyNoInteractions();
            });

        }
    }

    @Test
    void testStaticMockWithMoMoreInteractions() {
        try (MockedStatic<Dummy> dummy = mockStatic(Dummy.class)) {
            dummy.when(Dummy::foo).thenReturn("bar");
            assertEquals("bar", Dummy.foo());
            dummy.verify(Dummy::foo);
            dummy.verifyNoMoreInteractions();
        }
    }

    void testStaticMockWithMoMoreInteractionsFailed() {
        try (MockedStatic<Dummy> dummy = mockStatic(Dummy.class)) {
            dummy.when(Dummy::foo).thenReturn("bar");
            assertEquals("bar", Dummy.foo());
            assertThrows(NoInteractionsWanted.class, () -> {
                dummy.verifyNoMoreInteractions();
            });
        }
    }

    @Test
    void testStaticMockWithDefaultAnswer() {
        try (MockedStatic<Dummy> dummy = mockStatic(Dummy.class, invocation -> "bar")) {
            assertEquals("bar", Dummy.foo());
            dummy.verify(Dummy::foo);
        }
    }

    @Test
    void testStaticMockWithRealMethodCall() {
        try (MockedStatic<Dummy> dummy = mockStatic(Dummy.class)) {
            dummy.when(Dummy::foo).thenCallRealMethod();
            assertEquals("foo", Dummy.foo());
            dummy.verify(Dummy::foo);
        }
    }

    @Test
    void testStaticMockReset() {
        try (MockedStatic<Dummy> dummy = mockStatic(Dummy.class)) {
            dummy.when(Dummy::foo).thenReturn("bar");
            dummy.reset();
            assertNull(Dummy.foo());
        }
    }

    @Test
    void testStaticMockClear() {
        try (MockedStatic<Dummy> dummy = mockStatic(Dummy.class)) {
            dummy.when(Dummy::foo).thenReturn("bar");
            assertEquals("bar", Dummy.foo());
            dummy.clearInvocations();
            dummy.verifyNoInteractions();
        }
    }

    @Test
    void testStaticMockDoesNotAffectDifferentThread() throws InterruptedException {
        try (MockedStatic<Dummy> dummy = mockStatic(Dummy.class)) {
            dummy.when(Dummy::foo).thenReturn("bar");
            assertEquals("bar", Dummy.foo());
            dummy.verify(Dummy::foo);
            AtomicReference<String> reference = new AtomicReference<>();
            Thread thread = new Thread(() -> reference.set(Dummy.foo()));
            thread.start();
            thread.join();
            assertEquals("foo", reference.get());
            dummy.when(Dummy::foo).thenReturn("bar");
            assertEquals("bar", Dummy.foo());
            dummy.verify(times(2), Dummy::foo);
        }
    }

    @Test
    void testStaticMockCanCoexistWithMockInDifferentThread() throws InterruptedException {
        try (MockedStatic<Dummy> dummy = mockStatic(Dummy.class)) {
            dummy.when(Dummy::foo).thenReturn("bar");
            assertEquals("bar", Dummy.foo());
            dummy.verify(Dummy::foo);
            AtomicReference<String> reference = new AtomicReference<>();
            Thread thread = new Thread(() -> {
                try (MockedStatic<Dummy> dummy2 = mockStatic(Dummy.class)) {
                    dummy2.when(Dummy::foo).thenReturn("qux");
                    reference.set(Dummy.foo());
                }
            });
            thread.start();
            thread.join();
            assertEquals("qux", reference.get());
            dummy.when(Dummy::foo).thenReturn("bar");
            assertEquals("bar", Dummy.foo());
            dummy.verify(times(2), Dummy::foo);
        }
    }

    void testStaticMockMustBeExclusiveInScopeWithinThread() {

        try {
            try (MockedStatic<Dummy> dummy = mockStatic(Dummy.class);
                    MockedStatic<Dummy> duplicate = mockStatic(Dummy.class)) {

                fail("Not supposed to allow duplicates");
            }

        } catch (Exception e) {
            assertEquals(MockitoException.class, e.getClass());
        }
    }

    @Test
    void testStaticMockVoid() {
        try (MockedStatic<Dummy> dummy = mockStatic(Dummy.class)) {
            Dummy.fooVoid("bar");
            assertNull(Dummy.var1);
            dummy.verify(() -> Dummy.fooVoid("bar"));
        }
        Dummy.fooVoid("bar");
        assertEquals("bar", Dummy.var1);
    }

    static class Dummy {

        static String var1 = null;

        static String foo() {
            return "foo";
        }

        static void fooVoid(String var2) {
            var1 = var2;
        }
    }
}

16. Exercise: Using Spy and reflection to change private fields

Mockito can currently not mock private fields or methods. Changing private fields or methods during test should be avoided you should try to refactor you code.

Technically you could use a combination with @Spy and Java reflection access. This exercise demonstrates that.

16.1. Create data model

Create the following class.

package com.vogella.mockito.withprivate;

public class MyClassWithPrivateFieldAndMethod {

    public String field1 = "";
    public String valueSetByPrivateMethod = "";
    private String hiddenField = "initial";

    public String getValue() {
        return hiddenField;
    }

    public String getValueSetByPrivateMethod() {
        return valueSetByPrivateMethod;
    }

    public String toBeMockedByMockito() {
        return "stuff";
    }

    private void meineMethod() {
        valueSetByPrivateMethod = "lalal";
    }
}

16.2. Use Spy and reflection

Now assume you want to write a test and mock the toBeMockedByMockito method.

package com.vogella.mockito;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;

import com.vogella.mockito.withprivate.MyClassWithPrivateFieldAndMethod;

@ExtendWith(MockitoExtension.class)
class MyClassWithPrivateFieldAndMethodTest {

    @Spy
    MyClassWithPrivateFieldAndMethod mock = new MyClassWithPrivateFieldAndMethod();

    @Test
    void ensureSpyAndReflectiveAccessCanChangeAPrivateField() throws NoSuchFieldException, SecurityException,
            IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        assertEquals("initial", mock.getValue());

        mock.field1 = "Hello";

        when(mock.toBeMockedByMockito()).thenReturn("mocked by Mockito");
        Field declaredField = MyClassWithPrivateFieldAndMethod.class.getDeclaredField("hiddenField");
        declaredField.setAccessible(true);

        declaredField.set(mock, "changed");

        assertEquals("Hello", mock.field1);
        assertEquals("changed", mock.getValue());
        assertEquals("mocked by Mockito", mock.toBeMockedByMockito());
    }

}

16.3. Also call the private method

Use reflection to also call the private method and validate that the internal value was changed.

16.4. Another approach

Alternatively, you could implement a wrapper class for the class to be mocked which implements the internal differently or refactor your code.

17. Conclusion

Mockito makes it is easier to write unit tests by providing a powerful way of simulating and controlling dependencies.

The implementation of all these examples and code snippets can be found over on Mockito examples with Gradle.

18. Mockito resources