Everyday Mockito: A Guide for Unit Testing Practitioners

Editor’s note: This article was revised by our editorial staff on January 6, 2023. The update includes new resources and ensures it reflects our current editorial guidelines.

In the realm of Agile development, unit testing has become essential, and numerous tools are available to facilitate automated testing. Mockito, an open-source framework, stands out by enabling the creation and configuration of mock objects for testing purposes.

This article delves into the creation and configuration of mocks, utilizing them to validate the anticipated behavior of the system under test. Additionally, we will explore Mockito’s internal mechanisms to gain a deeper understanding of its design and potential limitations. While we employ JUnit as our unit testing framework, Mockito’s independence from JUnit allows you to follow along regardless of your preferred framework.

How Does Mockito Work?

Unit tests focus on testing the behavior of individual classes or methods in isolation from their dependencies. Since we’re examining the smallest “unit” of code, utilizing actual implementations of these dependencies is unnecessary. Moreover, slightly modified implementations of these dependencies are employed when testing different behaviors. A well-established approach involves creating “stubs,” which are tailored implementations of an interface suitable for a specific scenario. These implementations typically involve hard-coded logic. A stub represents a type of test double, alongside other types like fakes, mocks, spies, dummies, etc.

Our primary focus will be on “mocks” and “spies,” two prominent test double types extensively used in Mockito.

What Is a Mock?

Within unit testing, a mock serves as a crafted object that replicates the behavior of a real subsystem in a controlled manner. In essence, mocks act as substitutes for dependencies.

Mockito enables the creation of a mock, instructing it on how to respond when specific methods are invoked. This mock instance is then employed in tests instead of the actual dependency. Once testing is complete, the mock can be queried to determine which methods were called and examine any side effects in the form of state changes.

By default, Mockito automatically generates an implementation for every method of the mock.

What Is a Spy?

A spy represents another test double type generated by Mockito. Unlike mocks, spies necessitate an existing instance to spy on. By default, a spy delegates all method calls to the real object while recording the invoked method and its parameters. This behavior is what defines a spy – it observes and records the actions of a real object.

Whenever feasible, prioritize the use of mocks over spies. While spies might prove useful for testing legacy code that’s challenging to refactor for testability, the need for a spy to partially mock a class often indicates that the class has too many responsibilities, violating the single responsibility principle.

How Is Mockito Set Up?

Integrating Mockito is straightforward nowadays. For Gradle users, adding a single line to your build script is sufficient:

1
testCompile "org.mockito:mockito−core:2.7.7"

For those who, like me, still prefer Maven, simply add Mockito to your dependencies:

1
2
3
4
5
6
<dependency> 
    <groupId>org.mockito</groupId> 
    <artifactId>mockito-core</artifactId> 
    <version>2.7.7</version> 
    <scope>test</scope> 
</dependency>

Naturally, the world extends beyond Maven and Gradle. Feel free to use any project management tool to obtain the Mockito jar artifact from the Maven central repository.

Mockito Core Functions

Let’s transform our conceptual understanding of mocks and spies into tangible code functions applicable in Mockito unit testing.

A Simple Demo

Before diving into code samples, let’s establish a simple demo scenario for writing tests. Imagine we have a UserRepository interface with a single method for retrieving a user by their identifier. We also have the concept of a password encoder, responsible for converting plain-text passwords into password hashes. Both UserRepository and PasswordEncoder act as dependencies (or collaborators) of UserService, injected through the constructor. Here’s a representation of our demo code:

UserRepository:

1
2
3
public interface UserRepository {
   User findById(String id);
}

User:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public class User {

   private String id;
   private String passwordHash;
   private boolean enabled;

   public User(String id, String passwordHash, boolean enabled) {
       this.id = id;
       this.passwordHash = passwordHash;
       this.enabled = enabled;
   }
   // ...
}

PasswordEncoder:

1
2
3
public interface PasswordEncoder {
   String encode(String password);
}

UserService:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class UserService {

   private final UserRepository userRepository;
   private final PasswordEncoder passwordEncoder;

   public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) {
       this.userRepository = userRepository;
       this.passwordEncoder = passwordEncoder;
   }

   public boolean isValidUser(String id, String password) {
       User user = userRepository.findById(id);
       return isEnabledUser(user) && isValidPassword(user, password);
   }

   private boolean isEnabledUser(User user) {
       return user != null && user.isEnabled();
   }

   private boolean isValidPassword(User user, String password) {
       String encodedPassword = passwordEncoder.encode(password);
       return encodedPassword.equals(user.getPasswordHash());
   }
}

As we delve into various testing approaches, we will be referring back to our simple demo.

The Mockito mock Method

Creating a mock is effortlessly achieved by invoking the static Mockito.mock() method:

1
2
3
import static org.mockito.Mockito.*;
// ...
PasswordEncoder passwordEncoder = mock(PasswordEncoder.class);

Note the static import for Mockito. Throughout the remainder of this article, we assume this import is implicitly present.

Following the import, we mock the PasswordEncoder interface. It’s worth noting that Mockito can mock not only interfaces but also abstract classes and concrete non-final classes. Initially, Mockito couldn’t handle final classes and final or static methods, but the introduction of the MockMaker plugin has addressed this limitation.

Keep in mind that the equals() and hashCode() methods cannot be mocked.

The Mockito spy Method

Creating a spy involves calling Mockito’s static spy() method and passing an instance to spy on. Unless stubbed, invoking methods on the returned object will delegate the calls to the real object while recording the method call and its parameters. This spying characteristic allows for verifying interactions with the real object. Let’s create a spy:

1
2
DecimalFormat decimalFormat = spy(new DecimalFormat());
assertEquals("42", decimalFormat.format(42L));

The processes of creating a spy and a mock are quite similar. Moreover, all Mockito methods used for configuring a mock are applicable to spies as well.

While spies are used less frequently than mocks, they can be valuable when testing legacy code that resists refactoring and requires partial mocking. In such cases, a spy can be created, and specific methods can be stubbed to achieve the desired behavior.

Default Return Values

Invoking mock(PasswordEncoder.class) returns an instance of PasswordEncoder, allowing you to call its methods. However, the question arises: what will these methods return? By default, all methods of a mock return “uninitialized” or “empty” values. For instance, numeric types (both primitive and boxed) return zeros, booleans return false, and most other types return null.

Let’s consider the following interface:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
interface Demo {
   int getInt();
   Integer getInteger();
   double getDouble();
   boolean getBoolean();
   String getObject();
   Collection<String> getCollection();
   String[] getArray();
   Stream<?> getStream();
   Optional<?> getOptional();
}

Now, examine the following snippet, which illustrates the default values returned by a mock’s methods:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Demo demo = mock(Demo.class);
assertEquals(0, demo.getInt());
assertEquals(0, demo.getInteger().intValue());
assertEquals(0d, demo.getDouble(), 0d);
assertFalse(demo.getBoolean());
assertNull(demo.getObject());
assertEquals(Collections.emptyList(), demo.getCollection());
assertNull(demo.getArray());
assertEquals(0L, demo.getStream().count());
assertFalse(demo.getOptional().isPresent());

Testing: Stubbing Methods

Newly created mocks, in their unaltered state, have limited usefulness. Typically, we aim to configure the mock and define its behavior when specific methods are invoked. This process is referred to as “stubbing.”

Using Mockito thenReturn

Mockito offers two primary stubbing approaches. The first approach follows the pattern: “when this method is called, then do something.” This strategy utilizes Mockito’s thenReturn method:

1
when(passwordEncoder.encode("1")).thenReturn("a");

In simpler terms: “When passwordEncoder.encode(“1”) is called, return the string ‘a’.”

The second stubbing approach is phrased as: “do something when this mock’s method is called with the following arguments.” This approach can be less readable as the cause (method call with arguments) is specified at the end. Consider:

1
doReturn("a").when(passwordEncoder).encode("1");

This snippet, using the second stubbing method, translates to: “Return ‘a’ when the encode() method of passwordEncoder is invoked with the argument ‘1’.”

The first approach is generally preferred due to its type safety and enhanced readability. However, the second approach might be necessary in certain situations, such as when stubbing a real method of a spy to avoid unintended side effects from calling the actual method.

Let’s briefly examine the various stubbing methods provided by Mockito, showcasing both stubbing approaches in our examples.

Returning Values

Mockito’s thenReturn or doReturn() methods specify the value returned upon method invocation.

1
2
3
4
5
6
//“when this method is called, then do something”
when(passwordEncoder.encode("1")).thenReturn("a");


//“do something when this mock’s method is called with the following arguments”
doReturn("a").when(passwordEncoder).encode("1");

Multiple values can also be specified, determining the return values for consecutive method calls. The last specified value will be used as the return value for all subsequent calls.

1
2
3
4
5
//when
when(passwordEncoder.encode("1")).thenReturn("a", "b");

//do
doReturn("a", "b").when(passwordEncoder).encode("1");

The same outcome can be achieved with the following code:

1
2
3
when(passwordEncoder.encode("1"))
       .thenReturn("a")
       .thenReturn("b");

This pattern extends to other stubbing methods, enabling the definition of return values for a sequence of calls.

Returning Custom Responses

then(), an alias for thenAnswer(), and doAnswer() serve the same purpose: setting up a custom response to be returned upon method invocation.

1
2
3
4
5
6
7
8
//thenAnswer
when(passwordEncoder.encode("1")).thenAnswer(
       invocation -> invocation.getArgument(0) + "!");


//doAnswer
doAnswer(invocation -> invocation.getArgument(0) + "!")
       .when(passwordEncoder).encode("1");

thenAnswer() accepts a single argument, which is an implementation of the Answer interface. This interface has a single method with a parameter of type InvocationOnMock.

Throwing an exception as a result of a method call is also possible:

1
2
3
when(passwordEncoder.encode("1")).thenAnswer(invocation -> {
   throw new IllegalArgumentException();
});

Alternatively, you can choose to call the real method of a class (not applicable to interfaces):

1
2
3
4
5
Date mock = mock(Date.class);
doAnswer(InvocationOnMock::callRealMethod).when(mock).setTime(42);
doAnswer(InvocationOnMock::callRealMethod).when(mock).getTime();
mock.setTime(42);
assertEquals(42, mock.getTime());

You’re right if you find this approach somewhat cumbersome. Mockito provides the thenCallRealMethod() and thenThrow() methods to streamline this aspect of testing.

Calling Real Methods

As their names suggest, thenCallRealMethod() and doCallRealMethod() invoke the actual method on a mock object.

1
2
3
4
5
Date mock = mock(Date.class);
when(mock.getTime()).thenCallRealMethod();
doCallRealMethod().when(mock).setTime(42);
mock.setTime(42);
assertEquals(42, mock.getTime());

Calling real methods can be beneficial with partial mocks, but it’s crucial to ensure that the invoked method doesn’t produce unintended side effects or rely on object state. If it does, using a spy might be more appropriate than a mock.

Attempting to configure a stub to call a real method when mocking an interface will result in an exception with a descriptive error message from Mockito. Consider the following:

1
when(passwordEncoder.encode("1")).thenCallRealMethod();

Mockito will raise an error with the following message:

1
2
3
4
Cannot call abstract real method on java object!
Calling real methods is only possible when mocking non-abstract method.
  //correct example:
  when(mockOfConcreteClass.nonAbstractMethod()).thenCallRealMethod();

The Mockito developers deserve praise for providing such comprehensive error descriptions.

Throwing Exceptions

The thenThrow() and doThrow() methods configure a mocked method to throw an exception.

1
2
3
4
5
6
//thenThrow
when(passwordEncoder.encode("1")).thenThrow(new IllegalArgumentException());


//doThrow
doThrow(new IllegalArgumentException()).when(passwordEncoder).encode("1");

Mockito validates that the thrown exception is valid for the stubbed method. It will raise an error if the exception is not included in the method’s list of checked exceptions. Consider this example:

1
when(passwordEncoder.encode("1")).thenThrow(new IOException());

This code will lead to an error:

1
2
3
org.mockito.exceptions.base.MockitoException: 
Checked exception is invalid for this method!
Invalid: java.io.IOException

As demonstrated, Mockito detected that encode() is not designed to throw an IOException.

Instead of passing an exception instance, you can provide the exception’s class:

1
2
3
4
5
6
//thenThrow
when(passwordEncoder.encode("1")).thenThrow(IllegalArgumentException.class);


//doThrow
doThrow(IllegalArgumentException.class).when(passwordEncoder).encode("1");

However, Mockito cannot validate an exception class as rigorously as it validates an exception instance. Therefore, it’s crucial to exercise caution and avoid passing invalid class objects. For instance, the following code will throw an IOException even though encode() is not expected to throw a checked exception:

1
2
when(passwordEncoder.encode("1")).thenThrow(IOException.class);
passwordEncoder.encode("1");

Mocking Interfaces With Default Methods

It’s important to remember that when mocking an interface, Mockito mocks all its methods, including default methods introduced in Java 8. Consequently, you need to ensure that default methods behave as intended.

Consider this illustration:

1
2
3
4
5
6
7
interface AnInterface {
   default boolean isTrue() {
       return true;
   }
}
AnInterface mock = mock(AnInterface.class);
assertFalse(mock.isTrue());

In this scenario, assertFalse() will pass. If this behavior is unexpected, ensure that you’ve instructed Mockito to invoke the real method:

1
2
3
AnInterface mock = mock(AnInterface.class);
when(mock.isTrue()).thenCallRealMethod();
assertTrue(mock.isTrue());

Testing: Argument Matchers

In the preceding sections, we configured our mocked methods using specific values as arguments. In such cases, Mockito internally relies on the equals() method to determine if the expected values match the actual values.

However, there are scenarios where the exact values might not be known beforehand.

Perhaps you’re indifferent to the precise argument value or need to define a behavior for a broader range of values. Argument matchers come into play in these situations. Instead of providing exact values, you provide an argument matcher, allowing Mockito to match method arguments against it.

Consider this snippet:

1
2
3
when(passwordEncoder.encode(anyString())).thenReturn("exact");
assertEquals("exact", passwordEncoder.encode("1"));
assertEquals("exact", passwordEncoder.encode("abc"));

Regardless of the value passed to encode(), the result remains consistent because we utilized the anyString() argument matcher. Rephrasing the first line in plain English: “When the password encoder is requested to encode any string, return the string ‘exact’.”

Mockito mandates that all arguments are provided either as matchers or exact values. Consequently, if a method has multiple arguments and you intend to use argument matchers for only a subset of them, it won’t be possible. You cannot have code like this:

1
2
3
4
5
6
abstract class AClass {
   public abstract boolean call(String s, int i);
}
AClass mock = mock(AClass.class);
//This doesn’t work.
when(mock.call("a", anyInt())).thenReturn(true);

To resolve this error, you need to replace the last line and include the eq argument matcher for ‘a’:

1
when(mock.call(eq("a"), anyInt())).thenReturn(true);

In this example, we’ve used the eq() and anyInt() argument matchers. However, numerous other argument matchers are available. For a comprehensive list, refer to the documentation for the org.mockito.ArgumentMatchers class.

It’s crucial to emphasize that argument matchers cannot be used outside of verification or stubbing. For instance, the following code is invalid:

1
2
3
//This won’t work.
String orMatcher = or(eq("a"), endsWith("b"));
verify(mock).encode(orMatcher);

Mockito will detect the misplaced argument matcher and throw an InvalidUseOfMatchersException. Verification involving argument matchers should be performed as follows:

1
verify(mock).encode(or(eq("a"), endsWith("b")));

Similarly, argument matchers cannot be used as return values. Mockito requires an exact value when stubbing calls, so returning anyString() or any other matcher is not allowed.

Custom Matchers

When the matching logic required is not readily available in Mockito’s built-in matchers, custom matchers provide a solution. However, the decision to create a custom matcher should not be taken lightly. The need for non-trivial argument matching might indicate underlying design issues or overly complex tests.

Before resorting to custom matchers, it’s worth exploring if simplifying the test using lenient argument matchers like isNull() and nullable() is possible. If a custom matcher remains necessary, Mockito provides a set of methods to facilitate their creation.

Let’s illustrate with an example:

1
2
3
4
5
FileFilter fileFilter = mock(FileFilter.class);
ArgumentMatcher<File> hasLuck = file -> file.getName().endsWith("luck");
when(fileFilter.accept(argThat(hasLuck))).thenReturn(true);
assertFalse(fileFilter.accept(new File("/deserve")));
assertTrue(fileFilter.accept(new File("/deserve/luck")));

In this example, we define the hasLuck argument matcher. We then use argThat() to pass this matcher as an argument to the mocked method, stubbing it to return true if the filename ends with “luck.” You can treat ArgumentMatcher as a functional interface and instantiate it using a lambda expression (as done in the example). A less concise syntax would be:

1
2
3
4
5
6
ArgumentMatcher<File> hasLuck = new ArgumentMatcher<File>() {
   @Override
   public boolean matches(File file) {
       return file.getName().endsWith("luck");
   }
};

Mockito offers specialized methods within org.mockito.ArgumentMatchers for creating argument matchers that operate on primitive types:

  • charThat(ArgumentMatcher matcher)
  • booleanThat(ArgumentMatcher matcher)
  • byteThat(ArgumentMatcher matcher)
  • shortThat(ArgumentMatcher matcher)
  • intThat(ArgumentMatcher matcher)
  • longThat(ArgumentMatcher matcher)
  • floatThat(ArgumentMatcher matcher)
  • doubleThat(ArgumentMatcher matcher)

Combining Matchers

Creating a custom argument matcher might not always be necessary when a condition becomes too complex for basic matchers. Combining existing matchers can sometimes provide a sufficient solution. Mockito offers argument matchers to implement common logical operations (“not,” “and,” “or”) on argument matchers for both primitive and non-primitive types. These matchers are available as static methods within the the org.mockito.AdditionalMatchers class class.

Consider this example:

1
2
3
4
when(passwordEncoder.encode(or(eq("1"), contains("a")))).thenReturn("ok");
assertEquals("ok", passwordEncoder.encode("1"));
assertEquals("ok", passwordEncoder.encode("123abc"));
assertNull(passwordEncoder.encode("123"));

Here, we’ve combined the results of two argument matchers: eq("1") and contains("a"). The final expression, or(eq("1"), contains("a")), can be interpreted as “the argument string must either be equal to ‘1’ or contain ‘a’.”

It’s worth noting that the org.mockito.AdditionalMatchers class provides less commonly used matchers such as geq(), leq(), gt(), and lt(), which are value comparisons applicable to primitive values and instances of java.lang.Comparable.

Testing: Verifying Behavior

Once a mock or spy has been utilized, we can verify that specific interactions occurred. Essentially, we’re instructing Mockito to ensure that a method was called with the expected arguments.

Let’s examine an artificial example:

1
2
3
4
PasswordEncoder passwordEncoder = mock(PasswordEncoder.class);
when(passwordEncoder.encode("a")).thenReturn("1");
passwordEncoder.encode("a");
verify(passwordEncoder).encode("a");

We begin by setting up a mock and calling its encode() method. The final line verifies that the encode() method of the mock was invoked with the argument value a. Keep in mind that verifying a stubbed invocation is redundant. The purpose of this snippet is to illustrate the concept of performing verification after interactions have taken place.

Modifying the last line to use a different argument, say b, would cause the test to fail. Mockito would report that the actual invocation used different arguments (b instead of the expected a).

Similar to stubbing, argument matchers can be employed for verification:

1
verify(passwordEncoder).encode(anyString());

By default, Mockito verifies that the method was called once. However, you can specify a different number of invocations:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// verify the exact number of invocations
verify(passwordEncoder, times(42)).encode(anyString());

// verify that there was at least one invocation
verify(passwordEncoder, atLeastOnce()).encode(anyString());

// verify that there were at least 5 invocations
verify(passwordEncoder, atLeast(5)).encode(anyString());

// verify the maximum number of invocations
verify(passwordEncoder, atMost(5)).encode(anyString());

// verify that it was the only invocation and
// that there are no more unverified interactions
verify(passwordEncoder, only()).encode(anyString());

// verify that there were no invocations
verify(passwordEncoder, never()).encode(anyString());

A less frequently used feature of verify() is its ability to fail based on a timeout, primarily useful for testing concurrent code. For instance, if our password encoder is called concurrently with verify() in a separate thread, we can write a test like this:

1
2
usePasswordEncoderInOtherThread();
verify(passwordEncoder, timeout(500)).encode("a");

This test will pass if the encode() method is invoked and completes within 500 milliseconds or less. To enforce waiting for the full specified duration, use after() instead of timeout():

1
verify(passwordEncoder, after(500)).encode("a");

More sophisticated tests can be constructed by combining other verification modes (times(), atLeast(), etc.) with timeout() and after():

1
2
// passes as soon as encode() has been called 3 times within 500 ms
verify(passwordEncoder, timeout(500).times(3)).encode("a");

Besides times(), supported verification modes include only(), atLeast(), atLeastOnce() (an alias for atLeast(1)).

Mockito also enables the verification of call order within a group of mocks. While not a frequently used feature, it can be valuable when the order of invocations is critical. Consider this example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
PasswordEncoder first = mock(PasswordEncoder.class);
PasswordEncoder second = mock(PasswordEncoder.class);
// simulate calls
first.encode("f1");
second.encode("s1");
first.encode("f2");
// verify call order
InOrder inOrder = inOrder(first, second);
inOrder.verify(first).encode("f1");
inOrder.verify(second).encode("s1");
inOrder.verify(first).encode("f2");

Altering the sequence of simulated calls would cause the test to fail with a VerificationInOrderFailure.

The absence of invocations can also be verified using verifyZeroInteractions(). This method accepts one or more mocks as arguments and will fail if any method of the provided mock(s) was called.

Another noteworthy method is verifyNoMoreInteractions(), which takes mocks as arguments and checks if every call on those mocks has been verified.

Capturing Arguments

Beyond verifying that a method was called with specific arguments, Mockito allows capturing those arguments for later assertions. This capability enables you to verify method invocation while obtaining the argument values used in the call.

Let’s create a mock of PasswordEncoder, call encode(), capture the argument, and inspect its value:

1
2
3
4
5
PasswordEncoder passwordEncoder = mock(PasswordEncoder.class);
passwordEncoder.encode("password");
ArgumentCaptor<String> passwordCaptor = ArgumentCaptor.forClass(String.class);
verify(passwordEncoder).encode(passwordCaptor.capture());
assertEquals("password", passwordCaptor.getValue());

In this example, we pass passwordCaptor.capture() as an argument to encode() for verification. This creates an internal argument matcher that stores the argument. We then retrieve the captured value using passwordCaptor.getValue() and examine it with assertEquals().

To capture an argument across multiple calls, ArgumentCaptor provides the getAllValues() method to retrieve all captured values:

1
2
3
4
5
6
7
8
PasswordEncoder passwordEncoder = mock(PasswordEncoder.class);
passwordEncoder.encode("password1");
passwordEncoder.encode("password2");
passwordEncoder.encode("password3");
ArgumentCaptor<String> passwordCaptor = ArgumentCaptor.forClass(String.class);
verify(passwordEncoder, times(3)).encode(passwordCaptor.capture());
assertEquals(Arrays.asList("password1", "password2", "password3"),
             passwordCaptor.getAllValues());

This technique extends to capturing arguments for variable arity methods (varargs).

Testing: Simple Mockito Example

Armed with a deeper understanding of Mockito’s testing functionalities, let’s revisit our Java Mockito demo and write a test for the isValidUser method:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
public class UserServiceTest {

   private static final String PASSWORD = "password";

   private static final User ENABLED_USER =
           new User("user id", "hash", true);

   private static final User DISABLED_USER =
           new User("disabled user id", "disabled user password hash", false);
  
   private UserRepository userRepository;
   private PasswordEncoder passwordEncoder;
   private UserService userService;

   @Before
   public void setup() {
       userRepository = createUserRepository();
       passwordEncoder = createPasswordEncoder();
       userService = new UserService(userRepository, passwordEncoder);
   }

   @Test
   public void shouldBeValidForValidCredentials() {
       boolean userIsValid = userService.isValidUser(ENABLED_USER.getId(), PASSWORD);
       assertTrue(userIsValid);

       // userRepository had to be used to find a user with id="user id"
       verify(userRepository).findById(ENABLED_USER.getId());

       // passwordEncoder had to be used to compute a hash of "password"
       verify(passwordEncoder).encode(PASSWORD);
   }

   @Test
   public void shouldBeInvalidForInvalidId() {
       boolean userIsValid = userService.isValidUser("invalid id", PASSWORD);
       assertFalse(userIsValid);

       InOrder inOrder = inOrder(userRepository, passwordEncoder);
       inOrder.verify(userRepository).findById("invalid id");
       inOrder.verify(passwordEncoder, never()).encode(anyString());
   }

   @Test
   public void shouldBeInvalidForInvalidPassword() {
       boolean userIsValid = userService.isValidUser(ENABLED_USER.getId(), "invalid");
       assertFalse(userIsValid);

       ArgumentCaptor<String> passwordCaptor = ArgumentCaptor.forClass(String.class);
       verify(passwordEncoder).encode(passwordCaptor.capture());
       assertEquals("invalid", passwordCaptor.getValue());
   }

   @Test
   public void shouldBeInvalidForDisabledUser() {
       boolean userIsValid = userService.isValidUser(DISABLED_USER.getId(), PASSWORD);
       assertFalse(userIsValid);

       verify(userRepository).findById(DISABLED_USER.getId());
       verifyZeroInteractions(passwordEncoder);
   }

   private PasswordEncoder createPasswordEncoder() {
       PasswordEncoder mock = mock(PasswordEncoder.class);
       when(mock.encode(anyString())).thenReturn("any password hash");
       when(mock.encode(PASSWORD)).thenReturn(ENABLED_USER.getPasswordHash());
       return mock;
   }

   private UserRepository createUserRepository() {
       UserRepository mock = mock(UserRepository.class);
       when(mock.findById(ENABLED_USER.getId())).thenReturn(ENABLED_USER);
       when(mock.findById(DISABLED_USER.getId())).thenReturn(DISABLED_USER);
       return mock;
   }
}

Testing: Advanced Mockito Use

Mockito offers a clean and user-friendly API. However, delving into its internal workings can provide insights into its limitations and help avoid unexpected errors.

Ordering Calls

Let’s analyze what happens behind the scenes when the following code is executed:

1
2
3
4
5
6
7
8
// 1: create
PasswordEncoder mock = mock(PasswordEncoder.class);
// 2: stub
when(mock.encode("a")).thenReturn("1");
// 3: act
mock.encode("a");
// 4: verify
verify(mock).encode(or(eq("a"), endsWith("b")));

The first line creates a mock, a process where Mockito uses ByteBuddy to generate a subclass of the specified class. This new class is assigned a generated name, such as demo.mockito.PasswordEncoder$MockitoMock$1953422997. Its equals() method performs an identity check, and hashCode() returns an identity hash code. Once the class is generated and loaded, an instance is created using Objenesis.

Now, let’s examine the next line:

1
when(mock.encode("a")).thenReturn("1");

The order of operations is crucial here. The first statement executed is mock.encode("a"), which calls the encode() method on the mock. Since it’s not yet stubbed, it returns the default value of null. Therefore, we’re effectively passing null as an argument to when(). However, Mockito disregards the exact value passed to when() because it stores information about mocked method invocations in an “ongoing stubbing” object when the method is invoked. When when() is called, Mockito retrieves the ongoing stubbing object and returns it as the result. Finally, thenReturn(“1”) is called on the returned ongoing stubbing object.

The third line, mock.encode("a");, is straightforward. We’re invoking the now-stubbed method. Internally, Mockito records this invocation for later verification and returns the stubbed invocation’s answer, which is the string 1 in this case.

In the fourth line, verify(mock).encode(or(eq("a"), endsWith("b")));, we instruct Mockito to verify that an invocation of encode() occurred with the specified arguments.

The execution of verify() first puts Mockito into verification mode. It’s important to understand that Mockito manages its state using a ThreadLocal. While this enables a clean syntax, it can lead to unexpected behavior if the framework is used improperly, such as using argument matchers outside of verification or stubbing.

So, how does Mockito create an or matcher? Initially, eq("a") is called, pushing an equals matcher onto the matcher stack. Next, endsWith("b") is called, adding an endsWith matcher to the stack. Finally, or(null, null) is called. It pops the two matchers from the stack, creates the or matcher, and pushes it onto the stack. When encode() is called, Mockito verifies that the method was invoked the expected number of times and with the expected arguments.

While extracting argument matchers into variables is not possible (as it disrupts the call order), they can be extracted into methods. This approach preserves the call order, maintaining the stack’s integrity:

1
2
3
4
5
verify(mock).encode(matchCondition());
// ...
String matchCondition() {
   return or(eq("a"), endsWith("b"));
}

Changing Default Answers

Earlier, we created mocks that returned “empty” values when any mocked method was called. This default behavior can be customized. You can even provide a custom implementation of org.mockito.stubbing.Answer if Mockito’s predefined answers don’t suffice. However, overly complex unit tests might indicate underlying issues, and striving for simplicity is generally advisable.

Let’s explore Mockito’s predefined default answers:

RETURNS_DEFAULTSThe default strategy; it isn’t worth mentioning explicitly when setting up a mock.
CALLS_REAL_METHODSMakes unstubbed invocations call real methods.
RETURNS_SMART_NULLSAvoids a NullPointerException by returning SmartNull instead of null when using an object returned by an unstubbed method call. You’ll still fail with a NullPointerException, but SmartNull gives you a nicer stack trace with the line where an unstubbed method was called. This makes it worthwhile to have RETURNS_SMART_NULLS be the default answer in Mockito.
RETURNS_MOCKSFirst tries to return ordinary “empty” values, then mocks, if possible, and null otherwise. The criteria of emptiness differs a bit from what we’ve seen earlier: Instead of returning null for strings and arrays, the mocks created with RETURNS_MOCKS return empty strings and empty arrays, respectively.
RETURNS_SELFUseful for mocking builders. With this setting, a mock will return an instance of itself if a method is called that returns an object of a type equal to the class (or a superclass) of the mocked class.
RETURNS_DEEP_STUBSGoes deeper than RETURNS_MOCKS and creates mocks that are able to return mocks from mocks from mocks, etc. In contrast to RETURNS_MOCKS, the emptiness rules are default in RETURNS_DEEP_STUBS, so it returns null for strings and arrays:

interface We { Are we(); } interface Are { So are(); } interface So { Deep so(); } interface Deep { boolean deep(); } // ... We mock = mock(We.class, Mockito.RETURNS_DEEP_STUBS); when(mock.we().are().so().deep()).thenReturn(true); assertTrue(mock.we().are().so().deep());

Naming a Mock

Mockito allows assigning names to mocks, a helpful feature when dealing with numerous mocks in a test and needing to distinguish them. However, the need to name mocks could be a sign of suboptimal design. Consider the following:

1
2
3
PasswordEncoder robustPasswordEncoder = mock(PasswordEncoder.class);
PasswordEncoder weakPasswordEncoder = mock(PasswordEncoder.class);
verify(robustPasswordEncoder).encode(anyString());

Mockito will raise an error. However, without explicitly naming the mocks, it’s unclear which password encoder is being referenced:

1
2
Wanted but not invoked:
passwordEncoder.encode(<any string>);

Let’s name the mocks by providing a string during construction:

1
2
3
PasswordEncoder robustPasswordEncoder = mock(PasswordEncoder.class, "robustPasswordEncoder");
PasswordEncoder weakPasswordEncoder = mock(PasswordEncoder.class, "weakPasswordEncoder");
verify(robustPasswordEncoder).encode(anyString());

Now, the error message is more informative, clearly identifying robustPasswordEncoder:

1
2
Wanted but not invoked:
robustPasswordEncoder.encode(<any string>);

Implementing Multiple Mock Interfaces

There might be situations where you need a mock to implement multiple interfaces. Mockito readily accommodates this requirement:

1
2
3
4
PasswordEncoder mock = mock(
       PasswordEncoder.class, withSettings().extraInterfaces(List.class, Map.class));
assertTrue(mock instanceof List);
assertTrue(mock instanceof Map);

Listening Invocations

A mock can be configured to invoke an invocation listener every time one of its methods is called. Within the listener, you can determine if the invocation returned a value or threw an exception.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
InvocationListener invocationListener = new InvocationListener() {
   @Override
   public void reportInvocation(MethodInvocationReport report) {
       if (report.threwException()) {
           Throwable throwable = report.getThrowable();
           // do something with throwable
           throwable.printStackTrace();
       } else {
           Object returnedValue = report.getReturnedValue();
           // do something with returnedValue
           System.out.println(returnedValue);
       }
   }
};
PasswordEncoder passwordEncoder = mock(
       PasswordEncoder.class, withSettings().invocationListeners(invocationListener));
passwordEncoder.encode("1");

This example demonstrates dumping either the returned value or a stack trace to the system output stream. This implementation resembles Mockito’s internal org.mockito.internal.debugging.VerboseMockInvocationLogger (not intended for direct use). If logging invocations is the sole requirement, Mockito provides a more concise approach using the verboseLogging() setting:

1
2
PasswordEncoder passwordEncoder = mock(
       PasswordEncoder.class, withSettings().verboseLogging());

Keep in mind that Mockito invokes listeners even during method stubbing. Consider the following:

1
2
3
4
5
6
PasswordEncoder passwordEncoder = mock(
       PasswordEncoder.class, withSettings().verboseLogging());
// listeners are called upon encode() invocation
when(passwordEncoder.encode("1")).thenReturn("encoded1");
passwordEncoder.encode("1");
passwordEncoder.encode("2");

This snippet will generate output similar to:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
############ Logging method invocation #1 on mock/spy ########
passwordEncoder.encode("1");
   invoked: -> at demo.mockito.MockSettingsTest.verboseLogging(MockSettingsTest.java:85)
   has returned: "null"

############ Logging method invocation #2 on mock/spy ########
   stubbed: -> at demo.mockito.MockSettingsTest.verboseLogging(MockSettingsTest.java:85)
passwordEncoder.encode("1");
   invoked: -> at demo.mockito.MockSettingsTest.verboseLogging(MockSettingsTest.java:89)
   has returned: "encoded1" (java.lang.String)

############ Logging method invocation #3 on mock/spy ########
passwordEncoder.encode("2");
   invoked: -> at demo.mockito.MockSettingsTest.verboseLogging(MockSettingsTest.java:90)
   has returned: "null"

Notice that the first logged invocation corresponds to calling encode() during stubbing. The subsequent invocation represents the call to the stubbed method.

Other Settings

Mockito offers additional settings to:

  • Enable mock serialization: withSettings().serializable().
  • Disable method invocation recording to conserve memory (disabling verification): withSettings().stubOnly().
  • Utilize the mock’s constructor during instantiation: withSettings().useConstructor(). For mocking inner non-static classes, include outerInstance(): withSettings().useConstructor().outerInstance(outerObject).

To create a spy with custom settings, such as a custom name, use the spiedInstance() setting. Mockito will then create a spy on the provided instance:

1
2
3
4
5
UserService userService = new UserService(
       mock(UserRepository.class), mock(PasswordEncoder.class));
UserService userServiceMock = mock(
       UserService.class,
       withSettings().spiedInstance(userService).name("coolService"));

When a spied instance is specified, Mockito creates a new instance and populates its non-static fields with values from the original object. Consequently, it’s crucial to use the returned instance as only its method calls can be stubbed and verified.

Remember that creating a spy essentially involves creating a mock that calls real methods:

1
2
3
4
5
6
7
// creating a spy this way...
spy(userService);
// ... is a shorthand for
mock(UserService.class,
    withSettings()
            .spiedInstance(userService)
            .defaultAnswer(CALLS_REAL_METHODS));

Common Pitfalls of Mockito

It’s often our habits, rather than Mockito itself, that lead to complex and unmaintainable tests. For instance, feeling the urge to mock everything can result in testing mocks instead of the actual production code. Mocking third-party APIs can also be risky due to potential API changes that could break tests.

While perceptions of bad taste vary, Mockito offers a few debatable features that might hinder test maintainability. Stubbing can sometimes be non-trivial, and dependency injection abuse can make recreating mocks for each test cumbersome or inefficient.

Clearing Invocations

Mockito allows clearing invocations for mocks while preserving stubbing:

1
2
3
4
5
6
7
8
9
PasswordEncoder passwordEncoder = mock(PasswordEncoder.class);
UserRepository userRepository = mock(UserRepository.class);
// use mocks
passwordEncoder.encode(null);
userRepository.findById(null);
// clear
clearInvocations(passwordEncoder, userRepository);
// succeeds because invocations were cleared
verifyZeroInteractions(passwordEncoder, userRepository);

Clearing invocations should be reserved for situations where recreating a mock incurs significant overhead or when a configured mock is provided by a dependency injection framework, making stubbing complex.

Resetting a Mock

Resetting a mock using reset() is another controversial feature and should be used sparingly, such as when a mock is injected by a container, making per-test recreation impractical.

Overusing Verify

Another pitfall is attempting to replace every assertion with Mockito’s verify(). It’s essential to distinguish what’s being tested. Use verify() for checking interactions between collaborators and assertions for confirming the observable outcomes of executed actions.

Mockito As a Frame of Mind

Adopting Mockito extends beyond merely adding a dependency. It entails shifting your mindset towards unit testing while minimizing boilerplate code.

Through multiple mock interfaces, invocation listeners, matchers, and argument captors, Mockito empowers you to write cleaner and more comprehensible tests. However, like any tool, its effectiveness relies on proper usage. With an understanding of Mockito’s inner workings, you can elevate your unit testing practices.

Licensed under CC BY-NC-SA 4.0