0% found this document useful (0 votes)
63 views39 pages

Everyday Mockito

guide for mockito development

Uploaded by

omar
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
63 views39 pages

Everyday Mockito

guide for mockito development

Uploaded by

omar
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 39

® Developers

Engineering

BACK-END 22 MINUTE READ

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.

authors are vetted experts in their fields and write on topics in which they have demonstrated
experience. All of our content is peer reviewed and validated by Toptal experts in the same field.

By continuing to use this site you agree to our Cookie Policy. Got it
By Ivan Pavlov
Verified Expert in Engineering
17 Years of Experience

Ivan has both back-end and front-end development experience. He has built
software for banks, medical organizations, and city administration.
Read More

EXPERTISE

Java Unit Testing JUnit

SHARE

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 passwor


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 argumen
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

d h
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(), P
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(), "
assertFalse(userIsValid);

ArgumentCaptor<String> passwordCaptor = ArgumentCaptor.forClass(Strin


verify(passwordEncoder).encode(passwordCaptor.capture());
assertEquals("invalid", passwordCaptor.getValue());
}

@Test
public void shouldBeInvalidForDisabledUser() {
boolean userIsValid = userService.isValidUser(DISABLED_USER.getId(),
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:

The default strategy; it isn’t worth mentioning explicitly when


RETURNS_DEFAULTS
setting up a mock.

CALLS_REAL_METHODS Makes unstubbed invocations call real methods.

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
RETURNS_SMART_NULLS
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.

First tries to return ordinary “empty” values, then mocks, if


possible, and null otherwise. The criteria of emptiness differs a
RETURNS_MOCKS 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.

Useful for mocking builders. With this setting, a mock will return an
RETURNS_SELF 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.

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:
RETURNS_DEEP_STUBS 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, "robustP


PasswordEncoder weakPasswordEncoder = mock(PasswordEncoder.class, "weakPassw
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
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(invocationL
passwordEncoder.encode("1");

h l ’ d h h d l k
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(MockSettingsT
has returned: "null"

############ Logging method invocation #2 on mock/spy ########


stubbed: -> at demo.mockito.MockSettingsTest.verboseLogging(MockSettingsT
passwordEncoder.encode("1");
invoked: -> at demo.mockito.MockSettingsTest.verboseLogging(MockSettingsT
has returned: "encoded1" (java.lang.String)

############ Logging method invocation #3 on mock/spy ########


passwordEncoder.encode("2");
invoked: -> at demo.mockito.MockSettingsTest.verboseLogging(MockSettingsT
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 an outerInstance() 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:

A Guide to Robust Unit and Integration Tests with JUnit

Investing in Unit Testing: Benefits and Approaches


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?

What is the benefit of mocking?

Is mocking good practice?

TAGS Java mockito UnitTesting

Hire a Toptal expert on this topic.


Hire Now
Ivan Pavlov
Verified Expert in Engineering
17 Years of Experience

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.
Read More

authors are vetted experts in their fields and write on topics in which they have demonstrated
experience. All of our content is peer reviewed and validated by Toptal experts in the same field.

EXPERTISE

Java Unit Testing JUnit

Hire Ivan
TRENDING ARTICLES

ENGINEERING › TECHNOLOGY

5 Pillars of Responsible Generative AI: A Code of Ethics for


the Future

ENGINEERING › WEB FRONT-END

Tested Solutions: Working With React Design Patterns

ENGINEERING › DATA SCIENCE AND DATABASES

Advantages of AI: Using GPT and Diffusion Models for


Image Generation

ENGINEERING › DATA SCIENCE AND DATABASES

Ask an NLP Engineer: From GPT Models to the Ethics of AI

SEE OUR RELATED TALENT

Java Developers Unit Testing Experts JUnit Developers

VIEW RELATED SERVICES

Application Services and Modernization


World-class articles, delivered weekly.

Enter your email

Sign Me Up

Subscription implies consent to our privacy policy

Toptal Developers

Algorithm Developers Docker Developers R Developers

Angular Developers Elixir Developers React Native Developers

AWS Developers Go Engineers Ruby on Rails Developers

Azure Developers GraphQL Developers Salesforce Developers

Big Data Architects Jenkins Developers SQL Developers

Blockchain Developers Kotlin Developers Sys Admins


Business Intelligence Kubernetes Experts Tableau Developers
Developers
Machine Learning Engineers Unreal Engine Developers
C Developers
Magento Developers Xamarin Developers
Computer Vision Developers
.NET Developers View More Freelance Developers
Django Developers

Join the Toptal® community.

Hire a Developer

or
Apply as a Developer

ON-DEMAND TALENT MANAGEMENT CONSULTING

Hire Freelance Developers Finance and M&A

Hire Freelance Designers Innovation & Experience Consulting

Hire Freelance Finance Experts People & Organization Consulting

Hire Freelance Project Managers Sales Consulting

Hire Freelance Product Managers Strategy Consulting

Hire Freelance Marketers


TECHNOLOGY SERVICES

END-TO-END SOLUTIONS
Artificial Intelligence

Managed Delivery Application Services


Business Process Automation

Cloud Services

Data Analytics Consulting

Information Security Services

Quality Assurance Services

MARKETING SERVICES

Digital Marketing

Growth Marketing

ABOUT CONTACT

Top 3% Contact Us

Clients Press Center

Freelance Jobs Careers

Community FAQ

Specialized Services

Utilities & Tools

Research & Analysis Center

About Us

The World’s Top Talent, On Demand ®


Copyright 2010 - 2024 Toptal, LLC

Privacy Policy Website Terms Accessibility

You might also like