A Unit Testing Practitioner’s Guide to Everyday Mockito
Using Mockito is not just a matter of adding another dependency. It requires changing how you think about your unit tests while removing a lot of boilerplate. In this article, we cover multiple mock interfaces, listening invocations, matchers, and argument captors, and see firsthand how Mockito makes your tests cleaner and easier to understand.
Using Mockito is not just a matter of adding another dependency. It requires changing how you think about your unit tests while removing a lot of boilerplate. In this article, we cover multiple mock interfaces, listening invocations, matchers, and argument captors, and see firsthand how Mockito makes your tests cleaner and easier to understand.
Ivan has both back-end and front-end development experience. He has built software for banks, medical organizations, and city administration.
Expertise
Editor’s note: This article was updated by our editorial team on January 6, 2023. It has been modified to include recent sources and to align with our current editorial standards.
Unit testing has become mandatory in the age of Agile, and there are many tools available to help with automated testing. One such tool is Mockito, an open-source framework that lets you create and configure mocked objects for tests.
In this article, we cover creating and configuring mocks and using them to verify the expected behavior of the system being tested. We also explore Mockito’s internals to better understand its design and caveats. We use JUnit as a unit testing framework, but since Mockito is not bound to JUnit, you can follow along even if you’re using a different framework.
How Does Mockito Work?
Unit tests are designed to test the behavior of specific classes or methods without relying on the behavior of their dependencies. Since we’re testing the smallest “unit” of code, we don’t need to use actual implementations of these dependencies. Furthermore, we use slightly different implementations of these dependencies when testing different behaviors. A traditional, well-known approach here is to create “stubs”—specific implementations of an interface suitable for a given scenario. Such implementations usually have hard-coded logic. A stub is a kind of test double; other kinds of doubles include fakes, mocks, spies, dummies, etc.
We focus only on two types of test doubles, “mocks” and “spies,” as these are heavily employed by Mockito.
What Is a Mock?
In unit testing, a mock is a created object that implements the behavior of a real subsystem in controlled ways. In short, mocks are used as a replacement for a dependency.
With Mockito, you create a mock, tell Mockito what to do when specific methods are called on it, and then use the mock instance in your test instead of the real thing. After the test, you can query the mock to see what specific methods were called or check the side effects in the form of a changed state.
By default, Mockito provides an implementation for every method of the mock.
What Is a Spy?
A spy is the other type of test double that Mockito creates. In contrast to creating a mock, creating a spy requires an instance to spy on. By default, a spy delegates all method calls to the real object and records what method was called and with what parameters. That’s what makes it a spy: It’s spying on a real object.
Consider using mocks instead of spies whenever possible. Spies might be useful for testing legacy code that can’t be redesigned to be easily testable, but the need to use a spy to partially mock a class is an indicator that a class is doing too much, thus violating the single responsibility principle.
How Is Mockito Set Up?
Getting Mockito is easy these days. If you’re using Gradle, it’s a matter of adding this single line to your build script:
testCompile "org.mockito:mockito−core:2.7.7"
For those like me who still prefer Maven, just add Mockito to your dependencies:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.7.7</version>
<scope>test</scope>
</dependency>
Of course, the world is much wider than Maven and Gradle. You’re free to use any project management tool to fetch the Mockito jar artifact from the Maven central repository.
Mockito Core Functions
Let’s translate our conceptual definitions of mocks and spies into concrete code functions for use in Mockito unit testing.
A Simple Demo
Before discussing code examples, let’s have a look at a simple demo for which we can write tests. Suppose we have a UserRepository
interface with a single method to find a user by its identifier. We also have the concept of a password encoder to turn a clear-text password into a password hash. Both UserRepository
and PasswordEncoder
are dependencies (also called collaborators) of UserService
injected via the constructor. Here’s what our demo code looks like:
UserRepository:
public interface UserRepository {
User findById(String id);
}
User:
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:
public interface PasswordEncoder {
String encode(String password);
}
UserService:
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 discuss various testing strategies in this article, we will reference our simple demo.
The Mockito mock
Method
Creating a mock is as easy as calling a static Mockito.mock()
method:
import static org.mockito.Mockito.*;
// ...
PasswordEncoder passwordEncoder = mock(PasswordEncoder.class);
Notice the static import for Mockito. For the rest of this article, we implicitly consider this import added.
After the import, we mock out PasswordEncoder
, an interface. Mockito mocks not only interfaces but also abstract classes and concrete non-final classes. Out of the box, Mockito could not originally mock final classes and final or static methods, but the MockMaker plugin is now available.
Also note that the methods equals()
and hashCode()
cannot be mocked.
The Mockito spy
Method
To create a spy, you need to call Mockito’s static method spy()
and pass it an instance to spy on. Calling methods of the returned object will call real methods unless those methods are stubbed. These calls are recorded and the facts of these calls can be verified (see further description of verify()
). Let’s make a spy:
DecimalFormat decimalFormat = spy(new DecimalFormat());
assertEquals("42", decimalFormat.format(42L));
Creating a spy and creating a mock do not differ much. And all Mockito methods used for configuring a mock are also applicable to configuring a spy.
Spies are rarely used compared to mocks, but you may find them useful for testing legacy code that cannot be refactored, where testing requires partial mocking. In those cases, you can just create a spy and stub some of its methods to get the behavior you want.
Default Return Values
Calling mock(PasswordEncoder.class)
returns an instance of PasswordEncoder
. We can even call its methods, but what will they return? By default, all methods of a mock return “uninitialized” or “empty” values, e.g., zeros for numeric types (both primitive and boxed), false for booleans, and nulls for most other types.
Consider the following interface:
interface Demo {
int getInt();
Integer getInteger();
double getDouble();
boolean getBoolean();
String getObject();
Collection<String> getCollection();
String[] getArray();
Stream<?> getStream();
Optional<?> getOptional();
}
Now consider the following snippet, which gives an idea of what default values to expect from the methods of a mock:
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
Fresh, unaltered mocks are useful only in rare cases. Usually, we want to configure the mock and define what to do when specific methods of the mock are called. This is called stubbing.
Using Mockito thenReturn
Mockito offers two ways of stubbing. The first way is “when this method is called, then do something.” This strategy uses Mockito’s thenReturn
call:
when(passwordEncoder.encode("1")).thenReturn("a");
In plain English: “When passwordEncoder.encode(“1”)
is called, return an a
.”
The second way of stubbing reads more like “do something when this mock’s method is called with the following arguments.” This way of stubbing is harder to read as the cause is specified at the end. Consider:
doReturn("a").when(passwordEncoder).encode("1");
The snippet with this method of stubbing would read: “Return a
when passwordEncoder
’s encode()
method is called with an argument of 1
.”
The first way is preferred because it is typesafe and more readable. In rare circumstances you may be forced to use the second way, e.g., when stubbing a real method of a spy because calling it may have unwanted side effects.
Let’s briefly explore the stubbing methods provided by Mockito. We’ll include both ways of stubbing in our examples.
Returning Values
Mockito’s thenReturn
or doReturn()
is used to specify a value to be returned upon method invocation.
//“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");
You can also specify multiple values which will be returned as the results of consecutive method calls. The last value will be used as a result for all further method calls.
//when
when(passwordEncoder.encode("1")).thenReturn("a", "b");
//do
doReturn("a", "b").when(passwordEncoder).encode("1");
The same result can be achieved with the following snippet:
when(passwordEncoder.encode("1"))
.thenReturn("a")
.thenReturn("b");
This pattern can also be used with other stubbing methods to define the results of consecutive calls.
Returning Custom Responses
then()
, an alias to thenAnswer()
, and doAnswer()
achieve the same thing, which is to set up a custom answer to be returned when a method is called:
//thenAnswer
when(passwordEncoder.encode("1")).thenAnswer(
invocation -> invocation.getArgument(0) + "!");
//doAnswer
doAnswer(invocation -> invocation.getArgument(0) + "!")
.when(passwordEncoder).encode("1");
The only argument thenAnswer()
takes is an implementation of the Answer
interface. It has a single method with a parameter of type InvocationOnMock
.
You can also throw an exception as a result of a method call:
when(passwordEncoder.encode("1")).thenAnswer(invocation -> {
throw new IllegalArgumentException();
});
Alternatively, you may call the real method of a class (not applicable to interfaces):
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 think that it looks cumbersome. Mockito provides thenCallRealMethod()
and thenThrow()
to streamline this aspect of your testing.
Calling Real Methods
As the names suggest, thenCallRealMethod()
and doCallRealMethod()
call the real method on a mock object:
Date mock = mock(Date.class);
when(mock.getTime()).thenCallRealMethod();
doCallRealMethod().when(mock).setTime(42);
mock.setTime(42);
assertEquals(42, mock.getTime());
Calling real methods may be useful on partial mocks, but make sure that the called method has no unwanted side effects and doesn’t depend on object state. If it does, a spy may be a better fit than a mock.
If you create a mock of an interface and try to configure a stub to call a real method, Mockito will throw an exception with a very informative message. Consider the following snippet:
when(passwordEncoder.encode("1")).thenCallRealMethod();
Mockito will fail and give the following message:
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();
Kudos to the Mockito developers for caring enough to provide such thorough descriptions!
Throwing Exceptions
thenThrow()
and doThrow()
configure a mocked method to throw an exception:
//thenThrow
when(passwordEncoder.encode("1")).thenThrow(new IllegalArgumentException());
//doThrow
doThrow(new IllegalArgumentException()).when(passwordEncoder).encode("1");
Mockito ensures that the exception being thrown is valid for that specific stubbed method and will complain if the exception is not in the method’s checked exceptions list. Consider the following:
when(passwordEncoder.encode("1")).thenThrow(new IOException());
It will lead to an error:
org.mockito.exceptions.base.MockitoException:
Checked exception is invalid for this method!
Invalid: java.io.IOException
As you can see, Mockito detected that encode()
can’t throw an IOException
.
You can also pass an exception’s class instead of passing an instance of an exception:
//thenThrow
when(passwordEncoder.encode("1")).thenThrow(IllegalArgumentException.class);
//doThrow
doThrow(IllegalArgumentException.class).when(passwordEncoder).encode("1");
That said, Mockito cannot validate an exception class in the same way as it validates an exception instance, so you must be disciplined and not pass illegal class objects. For example, the following will throw IOException
though encode()
is not expected to throw a checked exception:
when(passwordEncoder.encode("1")).thenThrow(IOException.class);
passwordEncoder.encode("1");
Mocking Interfaces With Default Methods
It’s worth noting that when creating a mock for an interface, Mockito mocks all the methods of that interface. Since Java 8, interfaces may contain default methods along with abstract ones. These methods are also mocked, so you need to take care to make them act as default methods.
Consider the following example:
interface AnInterface {
default boolean isTrue() {
return true;
}
}
AnInterface mock = mock(AnInterface.class);
assertFalse(mock.isTrue());
In this example, assertFalse()
will succeed. If that’s not what you expected, make sure that you’ve had Mockito call the real method:
AnInterface mock = mock(AnInterface.class);
when(mock.isTrue()).thenCallRealMethod();
assertTrue(mock.isTrue());
Testing: Argument Matchers
In the previous sections, we configured our mocked methods with exact values as arguments. In those cases, Mockito just calls equals()
internally to check if the expected values are equal to the actual values.
Sometimes, though, we don’t know these values beforehand.
Maybe we just don’t care about the actual value being passed as an argument, or maybe we want to define a reaction for a wider range of values. All these scenarios (and others) can be addressed with argument matchers. The idea is simple: Instead of providing an exact value, you provide an argument matcher for Mockito to match method arguments against.
Consider the following snippet:
when(passwordEncoder.encode(anyString())).thenReturn("exact");
assertEquals("exact", passwordEncoder.encode("1"));
assertEquals("exact", passwordEncoder.encode("abc"));
You can see that the result is the same no matter what value we pass to encode()
because we used the anyString()
argument matcher in that first line. If we rewrote that line in plain English, it would be “when the password encoder is asked to encode any string, then return the string ‘exact.’”
Mockito requires you to provide all arguments either by matchers or by exact values. So if a method has more than one argument and you want to use argument matchers for only some of its arguments, it can’t be done. You can’t write code like this:
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 fix the error, we must replace the last line to include the eq
argument matcher for a
, as follows:
when(mock.call(eq("a"), anyInt())).thenReturn(true);
Here we’ve used the eq()
and anyInt()
argument matchers, but there are many others available. For a full list of argument matchers, refer to documentation on the org.mockito.ArgumentMatchers
class.
It’s important to note that you cannot use argument matchers outside of verification or stubbing. For example, you can’t have the following:
//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 with argument matchers should be done this way:
verify(mock).encode(or(eq("a"), endsWith("b")));
Argument matchers cannot be used as return value, either. Mockito can’t return anyString()
or any-whatever; an exact value is required when stubbing calls.
Custom Matchers
Custom matchers come to the rescue when you need to provide some matching logic that is not already available in Mockito. The decision to create a custom matcher shouldn’t be made lightly since the need to match arguments in a non-trivial way indicates either a design problem or a too-complicated test.
As such, it’s worth checking whether you can simplify a test by using some of the lenient argument matchers such as isNull()
and nullable()
before writing a custom matcher. If you still feel the need to write an argument matcher, Mockito provides a family of methods to do it.
Consider the following example:
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")));
Here we create the hasLuck
argument matcher and use argThat()
to pass the matcher as an argument to a mocked method, stubbing it to return true
if the filename ends with “luck.” You can treat ArgumentMatcher
as a functional interface and create its instance with a lambda (which is what we’ve done in the example). Less concise syntax would look like this:
ArgumentMatcher<File> hasLuck = new ArgumentMatcher<File>() {
@Override
public boolean matches(File file) {
return file.getName().endsWith("luck");
}
};
If you need to create an argument matcher that works with primitive types, there are several other methods for that in org.mockito.ArgumentMatchers
:
- charThat(ArgumentMatcher<Character> matcher)
- booleanThat(ArgumentMatcher<Boolean> matcher)
- byteThat(ArgumentMatcher<Byte> matcher)
- shortThat(ArgumentMatcher<Short> matcher)
- intThat(ArgumentMatcher<Integer> matcher)
- longThat(ArgumentMatcher<Long> matcher)
- floatThat(ArgumentMatcher<Float> matcher)
- doubleThat(ArgumentMatcher<Double> matcher)
Combining Matchers
It’s not always worth creating a custom argument matcher when a condition is too complicated to be handled with basic matchers; sometimes combining matchers will do the trick. Mockito provides argument matchers to implement common logical operations (“not,” “and,” “or”) on argument matchers that match both primitive and non-primitive types. These matchers are implemented as static methods on the org.mockito.AdditionalMatchers
class.
Consider the following example:
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"))
, may be interpreted as “the argument string must be equal to “1” or contain “a”.
Note that there are less common matchers listed on the org.mockito.AdditionalMatchers
class, such as geq()
, leq()
, gt()
, and lt()
, which are value comparisons applicable for primitive values and instances of java.lang.Comparable
.
Testing: Verifying Behavior
Once a mock or spy has been used, we can verify
that specific interactions took place. Literally, we are saying, “Hey, Mockito, make sure this method was called with these arguments.”
Consider the following artificial example:
PasswordEncoder passwordEncoder = mock(PasswordEncoder.class);
when(passwordEncoder.encode("a")).thenReturn("1");
passwordEncoder.encode("a");
verify(passwordEncoder).encode("a");
Here we’ve set up a mock and called its encode()
method. The last line verifies that the mock’s encode()
method was called with the specific argument value a
. Please note that verifying a stubbed invocation is redundant; the purpose of the previous snippet is to show the idea of doing verification after some interactions happened.
If we change the last line to have a different argument—say, b
—the previous test will fail and Mockito will complain that the actual invocation has different arguments (b
instead of the expected a
).
Argument matchers can be used for verification just as they are for stubbing:
verify(passwordEncoder).encode(anyString());
By default, Mockito verifies that the method was called once, but you can verify any number of invocations:
// 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 rarely used feature of verify()
is its ability to fail on a timeout, which is mainly useful for testing concurrent code. For example, if our password encoder is called in another thread concurrently with verify()
, we can write a test as follows:
usePasswordEncoderInOtherThread();
verify(passwordEncoder, timeout(500)).encode("a");
This test will succeed if encode()
is called and finished within 500 milliseconds or less. If you need to wait the full specified period, use after()
instead of timeout()
:
verify(passwordEncoder, after(500)).encode("a");
Other verification modes (times()
, atLeast()
, etc) can be combined with timeout()
and after()
to make more complicated tests:
// 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()
, and atLeastOnce()
(as an alias to atLeast(1)
).
Mockito also allows you to verify the call order in a group of mocks. It’s not a feature to use very often, but it may be useful if the order of invocations is important. Consider the following example:
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");
If we rearrange the order of the simulated calls, the test will fail with VerificationInOrderFailure
.
The absence of invocations can also be verified using verifyZeroInteractions()
. This method accepts a mock or mocks as an argument and will fail if any methods of the passed-in mock(s) were called.
It’s also worth mentioning the verifyNoMoreInteractions()
method, as it takes mocks as an argument and can be used to check that every call on those mocks was verified.
Capturing Arguments
Besides verifying that a method was called with specific arguments, Mockito allows you to capture those arguments so that you can later run custom assertions on them. In other words, you’re able to verify that a method was called, and receive the argument values it was called with.
Let’s create a mock of PasswordEncoder
, call encode()
, capture the argument, and check its value:
PasswordEncoder passwordEncoder = mock(PasswordEncoder.class);
passwordEncoder.encode("password");
ArgumentCaptor<String> passwordCaptor = ArgumentCaptor.forClass(String.class);
verify(passwordEncoder).encode(passwordCaptor.capture());
assertEquals("password", passwordCaptor.getValue());
As you can see, we pass passwordCaptor.capture()
as an argument of encode()
for verification; this internally creates an argument matcher that saves the argument. Then we retrieve the captured value with passwordCaptor.getValue()
and inspect it with assertEquals()
.
If we need to capture an argument across multiple calls, ArgumentCaptor
lets you retrieve all values with getAllValues()
:
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());
The same technique can be used for capturing variable arity method arguments (also known as varargs).
Testing: Simple Mockito Example
Now that we know a lot more about testing functionalities, it’s time to get back to our Java Mockito demo. Let’s write the isValidUser
method test. Here’s what it might look like:
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 provides a readable, convenient API, but let’s explore some of its internal workings to understand its limitations and avoid weird errors.
Ordering Calls
Let’s examine what’s going on inside Mockito when the following snippet is run:
// 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")));
Obviously, the first line creates a mock. Mockito uses ByteBuddy to create a subclass of the given class. The new class object has a generated name like demo.mockito.PasswordEncoder$MockitoMock$1953422997
; its equals()
will act as an identity check, and hashCode()
will return an identity hash code. Once the class is generated and loaded, its instance is created using Objenesis.
Let’s look at the next line:
when(mock.encode("a")).thenReturn("1");
The ordering is important: The first statement executed here is mock.encode("a")
, which will invoke encode()
on the mock with a default return value of null
. So really, we’re passing null
as an argument of when()
. Mockito doesn’t care what exact value is being passed to when()
because it stores information about a mocked method’s invocation in so-called “ongoing stubbing” when that method is invoked. Later, when we’re calling when()
, Mockito pulls that ongoing stubbing object and returns it as the result of when()
. Then we call thenReturn(“1”)
on the returned ongoing stubbing object.
The third line, mock.encode("a");
is simple: We’re calling the stubbed method. Internally, Mockito saves this invocation for further verification and returns the stubbed invocation answer; in our case, it’s the string 1
.
In the fourth line (verify(mock).encode(or(eq("a"), endsWith("b")));
), we’re asking Mockito to verify that there was an invocation of encode()
with those specific arguments.
verify()
is executed first, which turns Mockito’s internal state into verification mode. It’s important to understand that Mockito keeps its state in a ThreadLocal
. This makes it possible to implement a nice syntax, but, on the other hand, it can lead to weird behavior if the framework is used improperly (if you attempt to use argument matchers outside of verification or stubbing, for example).
So how does Mockito create an or
matcher? First, eq("a")
is called, and an equals
matcher is added to the matchers stack. Second, endsWith("b")
is called, and an endsWith
matcher is added to the stack. Last, or(null, null)
is called: It uses the two matchers it pops from the stack, creates the or
matcher, and pushes that to the stack. Finally, encode()
is called. Mockito then verifies that the method was invoked the expected number of times and with the expected arguments.
While argument matchers can’t be extracted to variables (because they change the call order), they can be extracted to methods. This preserves the call order and keeps the stack in the right state:
verify(mock).encode(matchCondition());
// ...
String matchCondition() {
return or(eq("a"), endsWith("b"));
}
Changing Default Answers
In previous sections, we created our mocks in such a way that when any mocked methods were called, they returned an “empty” value. This behavior is configurable. You can even provide your own implementation of org.mockito.stubbing.Answer
if those provided by Mockito are not suitable, but it might be an indication that something is wrong when unit tests get too complicated. When in doubt, strive for simplicity.
Let’s explore Mockito’s offering of predefined default answers:
RETURNS_DEFAULTS | The default strategy; it isn’t worth mentioning explicitly when setting up a mock. |
CALLS_REAL_METHODS | Makes unstubbed invocations call real methods. |
RETURNS_SMART_NULLS | Avoids 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_MOCKS | First 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_SELF | Useful 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_STUBS | Goes 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 you to name a mock, a useful feature if you have a lot of mocks in a test and need to distinguish them. That said, needing to name mocks might be a symptom of poor design. Consider the following:
PasswordEncoder robustPasswordEncoder = mock(PasswordEncoder.class);
PasswordEncoder weakPasswordEncoder = mock(PasswordEncoder.class);
verify(robustPasswordEncoder).encode(anyString());
Mockito will complain with an error message, but because we haven’t formally named the mocks, we don’t know which password encoder is being referred to:
Wanted but not invoked:
passwordEncoder.encode(<any string>);
Let’s name the mocks by passing in a string on construction:
PasswordEncoder robustPasswordEncoder = mock(PasswordEncoder.class, "robustPasswordEncoder");
PasswordEncoder weakPasswordEncoder = mock(PasswordEncoder.class, "weakPasswordEncoder");
verify(robustPasswordEncoder).encode(anyString());
Now the error message is friendlier and clearly points to robustPasswordEncoder
:
Wanted but not invoked:
robustPasswordEncoder.encode(<any string>);
Implementing Multiple Mock Interfaces
Sometimes, you may wish to create a mock that implements several interfaces. Mockito is able to do that easily:
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 call an invocation listener every time a method of the mock is called. Inside the listener, you can find out whether the invocation produced a value or if an exception was thrown.
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");
In this example, we’re dumping either the returned value or a stack trace to a system output stream. Our implementation does roughly what Mockito’s org.mockito.internal.debugging.VerboseMockInvocationLogger
does (but this is an internal implementation that should not be called directly). If logging invocations is the only feature you need from the listener, then Mockito provides a cleaner way to express your intent with the verboseLogging()
setting:
PasswordEncoder passwordEncoder = mock(
PasswordEncoder.class, withSettings().verboseLogging());
Notice that Mockito will call the listeners even when you’re stubbing methods. Consider the following example:
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 produce an output similar to the following:
############ 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"
Note that the first logged invocation corresponds to calling encode()
while stubbing it. It’s the next invocation that corresponds to calling the stubbed method.
Other Settings
Mockito offers a few more settings that let you do the following:
- Enable mock serialization by using
withSettings().serializable()
. - Turn off recording of method invocations to save memory (this will make verification impossible) by using
withSettings().stubOnly()
. - Use the constructor of a mock when creating its instance by using
withSettings().useConstructor()
. When mocking inner non-static classes, add anouterInstance()
setting:withSettings().useConstructor().outerInstance(outerObject)
.
If you need to create a spy with custom settings (such as a custom name), there’s a spiedInstance()
setting such that Mockito will create a spy on the instance you provide:
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 will create a new instance and populate its non-static fields with values from the original object. That’s why it’s important to use the returned instance: Only its method calls can be stubbed and verified.
Note that when you create a spy, you’re basically creating a mock that calls real methods:
// 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
Our bad habits make our tests complex and unmaintainable, not Mockito. For example, you may feel the need to mock everything. This kind of thinking leads to testing mocks instead of testing production code. Mocking third-party APIs can also be dangerous due to potential changes in that API that can break the tests.
Though bad taste is a matter of perception, Mockito provides a few controversial features that can make your tests less maintainable. Sometimes stubbing isn’t trivial, or an abuse of dependency injection can make recreating mocks for each test difficult, unreasonable, or inefficient.
Clearing Invocations
Mockito allows for clearing invocations for mocks while preserving stubbing:
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);
Resort to clearing invocations only if recreating a mock would lead to significant overhead or if a configured mock is provided by a dependency injection framework and stubbing is non-trivial.
Resetting a Mock
Resetting a mock with reset()
is another controversial feature and should be used in extremely rare cases, like when a mock is injected by a container and you can’t recreate it for each test.
Overusing Verify
Another bad habit is trying to replace every assert with Mockito’s verify()
. It’s important to clearly understand what is being tested: Interactions between collaborators can be checked with verify()
, while confirming the observable results of an executed action is done with asserts.
Mockito As a Frame of Mind
Using Mockito is not just a matter of adding another dependency; it requires changing how you think about your unit tests while removing a lot of boilerplate.
With multiple mock interfaces, listening invocations, matchers, and argument captors, we’ve seen how Mockito makes your tests cleaner and easier to understand, but, like any tool, it must be used properly to be useful. Now that you are armed with the knowledge of Mockito’s inner workings, you can take your unit testing to the next level.
Further Reading on the Toptal Blog:
Understanding the basics
What is Mockito used for?
Mockito is used to create and configure mocked objects (e.g., a mock or spy) when unit testing.
Why is mock testing important?
Using mocks in testing is important when it is not possible or practical to use real objects in a test. Mocks allow you to create an object that implements the behavior of a real subsystem in controlled ways.
What is the benefit of mocking?
Mocks offer an alternative to using dependencies in unit tests, since they avoid using real objects.
Is mocking good practice?
Yes, mocking thoughtfully and sparingly is good practice in cases where it is not possible to use real objects in tests. It is recommended to use mocks instead of spies whenever possible to help ensure that your classes do not violate the single responsibility principle.
Hamburg, Germany
Member since March 7, 2016
About the author
Ivan has both back-end and front-end development experience. He has built software for banks, medical organizations, and city administration.