So, in case you haven’t read the first part in this series,
which is giving some basic introduction to the idea of JUnit
testing – go ahead, I’ll wait till you’re back so that we can
proceed with the next steps.
👩 Yes, I’ve got the basics, go on.
Great. Let’s now proceed with getting testing support in case our System Under Test (SUT) has some collaborator objects,
which is the case most often, and we want to configure behavior of these objects in our SUT
tests.
For such a thing we’ll use Mockito
library. In real life our SUT
depends on other collaborators to help him complete his
responsibility. Might be that we’re about to build an app that is some sort of music streaming one, and we’re creating UserService
to list favorite playlists for current user. It may be that we’ll make UserService
dependant on PlaylistService
that is
capable of returning playlists for particular user.
So, in such a case, in order to test our UserService
in isolation, we’ll have to configure our collaborator – PlaylistService
in terms of behavior, so that we can test our UserService
for such a behavior(s).
During application runtime, in various situations, our collaborators might return some values, sometimes they return empty collections, or might throw an exception. Idea is that we’d like to mimic these kind of situations in our tests, so that we confirm our SUT works as planned for different collaborators behaviors.
👩 OK.. How do I get Mockito
? Hope I don’t need bunch of Jars downloaded and configured – just to get started.
No, not at all. We’ll continue coding from where we left off after completing the first part.
We’ll use Maven
to help us do dependency setup, so we’ll open our pom.xml and insert our dependency:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
All we had to do is inserting this snippet inside <dependencies>
tag of our pom.xml
. Maven
will get mockito-core-1.10.19.jar
downloaded for us and ready to use in our tests.
👩 Can I see Mockito
in action? You can explain me the details on the fly…
Sure. Once we did dependency setup, we can create simple test case to show the first basic steps. Let’s create MockListTest.java
package com.mydomain.mock_list;
import org.JUnit.Before;
import org.JUnit.Test;
import org.mockito.BDDMockito;
import org.mockito.Mock;
import org.mockito.MockingDetails;
import org.mockito.MockitoAnnotations;
import java.util.List;
import static org.JUnit.Assert.assertTrue;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
public class MockListTest {
@Mock
List<Integer> integerList;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
@Test
public void mockListWithoutAnnotations() throws Exception {
/* given */
final List mockedList = mock(List.class);
given(mockedList.get(3)).willReturn(3);
given(mockedList.size()).willReturn(1);
mockedList.add(2);
mockedList.add(3);
mockedList.add(4);
mockedList.add(5);
/* when */
final int listSize = mockedList.size();
/* then */
final MockingDetails mockingDetails = BDDMockito.mockingDetails(mockedList);
assertTrue(mockingDetails.getInvocations().size() == 5);
assertTrue(listSize == 1);
}
@Test
public void useInjectedMock() throws Exception {
given(integerList.size()).willReturn(1, 2, 3);
integerList.add(3);
assertTrue(integerList.size() == 1);
integerList.add(4);
assertTrue(integerList.size() == 2);
integerList.add(5);
assertTrue(integerList.size() == 3);
}
}
Let’s first analyze mockListWithoutAnnotations()
test method. We statically imported several Mockito
methods in imports area,
such as Mockito.mock
, BDDMockito.given
, so that our code is more readable. The first usage of Mockito
API is a call to mock()
method, which creates mocked instance of given interface / class.
👩 Mocked instance?
Yes. In real life we mock our collaborator objects. Here we just mocked an instance of List
interface. We use mocking to setup
some behavior of collaborators, and we want to check how our SUT
behaves in such a case.
Tests given above are not realistic since they don’t test any SUT
, here we’re just creating demo how to use APIs. mock
method
receives Class
parameter, which is the type we wan’t to mock.
Another way is to use @Mock
Mockito
annotation. We can just have a class field annotated with annotation and some additional plumbing:
- we should call
MockitoAnnotations.initMocks(this)
inside@Before
annotated setup method (it’s called by framework once before every test method is executed). - annotate Test class with
@RunWith(MockitoJUnitRunner.class)
👩 What happens if we don’t configure mocked object and it’s methods get called?
Non void
methods return by default an “empty” value appropriate for its type (null
, 0
, false
, empty collection).
👩 You said we can configure behavior of collaborator objects… How?
There’s a sequence called Arrange – Act – Assert (AAA) which is to be followed in JUnit
tests implementation. In Arrange
phase we create mock instances, and configure their behavior. After that, in Act phase, we call SUT
method we want tested. Finally,
in Assert phase, we assert various conditions to check if SUT
executed as expected in given context.
There’s another way to express your tests, which is part of Behavior Driven Development, which states test steps as Given – When – Then (GWT).
BDDMockito.given(mockedList.get(3)).willReturn(3)
is an example of stubbing mocks for expected behavior using GWT
. Pretty self explanatory – we
configure mock to return value 3 when mocked List instance is asked to return value at the index of 3.
BDDMockito.given
returns as a result instance of BDDMyOngoingStubbing
, which has the following API to use when stubbing mocks in our tests: willAnswer
,
will
, willReturn
, willThrow
, willCallRealMethod
. Most often you’ll probably use willReturn
and willThrow
when stubbing your collaborators.
Using AAA
style, we can configure the same stubbing as GWT
using Mockito.when(mockedList.get(2)).thenReturn(2)
syntax. We will not cover the differences
between AAA
and GWT
styles. I use GWT
style but you can use the one you feel comfortable with.
👩 What about argument matching?
Mockito
, by default, uses equals() for arguments matching. Let’s see it in action:
@Test
public void testArguments() throws Exception {
final String someString = "some string";
final String notMe = "not me";
final List<String> mockedList = (List<String>) mock(List.class);
given(mockedList.add(someString)).willReturn(true);
given(mockedList.add(Matchers.startsWith("can't add"))).willReturn(false);
given(mockedList.add(Matchers.eq(notMe))).willReturn(false);
assertTrue(mockedList.add(someString));
assertFalse(mockedList.add("can't add 1"));
assertFalse(mockedList.add("can't add 2"));
}
Matchers
and AdditionalMatchers
APIs provide large set of useful matchers we can use. We have fine grained control of configuring
mocks using these. Given above, we’re using Matchers.startsWith
and Matchers.eq
. So, we can configure mocks to return specific value
for exact value of argument it receives, or some other value if argument is / isn’t null, or in case of String
we can configure behavior
depending on if argument starts with some sequence, ends with, and so forth. Quite often you may find useful family of any()
methods,
so you can use it to mock methods of particular type, so if mock method receives int
you can mock it using Matchers.anyInt()
matcher.
👩 What about stubbing void
methods?
Let’s do it with an example:
@Test
public void stubVoidMethods() throws Exception {
List<String> list = ((List<String>) mock(List.class));
BDDMockito.willDoNothing().given(list).clear();
BDDMockito.willThrow(Exception.class).given(list).clear();
Mockito.doNothing().when(list).clear();
Mockito.doThrow(Exception.class).when(list).clear();
}
List.clear()
is a void
method, and we can configure void
methods to either do nothing (which is default, so we don’t need to
configure this) or to throw an exception, as shown in the snippet above.
👩 And how do I verify if mocked collaborators were actually called?
For such a purpose we can call Mockito.verify
API. Verification example:
@Test
public void verificationExample() throws Exception {
final Calculator calculator = mock(Calculator.class);
verify(calculator, Mockito.never()).add(anyLong(), anyLong());
calculator.divide(2, 5);
verify(calculator, times(1)).divide(2, 5);
verify(calculator, atMost(0)).multiply(anyLong(), anyLong());
verify(calculator, never()).add(anyLong(), anyLong());
Mockito.verifyZeroInteractions(calculator);
}
verify
has a following signature: Mockito.verify(Mock mock,VerificationMode mode)
. It receives VerificationMode
as second parameter,
and Mockito
class has some built-in verification modes at your disposal: times(int)
, atMost(int)
, never()
and so on. Given example
above should be pretty self-explanatory. Feel free to explore all verification modes and how to use them by reading Mockito
Javadoc.
Mockito
class also contains verifyZeroInteractions
static method that receives varargs of mocks, and returns true if there were no
interactions with given mocks, false otherwise.
👩 Can I capture actual value passed to mock, in order to make some asserts on it?
Great question! Mockito has ArgumentCaptor<T>
class that is to be used in such a case. Let’s show how to do that with simple example.
Say we have a class:
package com.mydomain.sut_and_collaborator;
public class MySystemUnderTest {
private Collaborator collaborator;
public MySystemUnderTest(Collaborator collaborator) {
this.collaborator = collaborator;
}
public boolean doSomeStuff(String withArgument) {
return collaborator.doStuff(withArgument);
}
}
Our Collaborator looks like:
package com.mydomain.sut_and_collaborator;
public class Collaborator {
public boolean doStuff(String withArgument) {
return withArgument.contains("some-thing");
}
}
Finally, we’re testing our system under test:
@Test
public void argumentCaptor() throws Exception {
final Collaborator collaborator = mock(Collaborator.class);
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
final boolean result = new MySystemUnderTest(collaborator).doSomeStuff("my param");
verify(collaborator).doStuff(captor.capture());
assertTrue(captor.getValue().equals("my param"));
assertFalse(result);
}
We’re calling doSomeStuff
on MySystemUnderTest
class. All it does is delegating a call to Collaborator
class. We want to assert that
collaborator object received expected value as an argument. In order to capture value that collaborator received, we need to create
ArgumentCaptor<T>
, where T
is type of argument method of collaborator object receives. In our case what gets executed is collaborator.doStuff(String arg)
.
So, we need argument captor of String
type. So, in order to capture value passed to collaborator during SUT
method test, we need to:
- Create
ArgumentCaptor<T>
instance - Execute method call on
SUT
(that calls our collaborator method) - verify collaborator method is executed passing
captor.capture()
as a method argument - call
captor.getValue()
to obtain captured value
ArgumentCaptor<T>
has also getAllValues() : List<T>
method, that either returns all values if collaborator method receives varargs, or,
in case method was called multiple times – list containing these values. Feel free to experiment with captor to get used to technique of
capturing mock method arguments. Argument captor can be created at a test class field level by just putting @Captor
annotation (note that
the same configuration is required as for @Mock
usage – described above) on the field itself, e.g:
@Captor
ArgumentCaptor captor;
👩 Can I somehow stub real objects behavior, not mocked ones only?
Yes, Mockito
provides support for that. Usually, you don’t want to mock real objects, but in case you need that, Mockito
has
Mockito.spy
API, as well as @Spy
annotation. Basic idea is that we need to create a spy (proxy object) that will delegate all
calls to real object, unless we say we want to override behavior of real object method(s). Example:
@Test
public void spyExample() throws Exception {
final MySystemUnderTest realSUT = new MySystemUnderTest(new Collaborator());
final MySystemUnderTest spySUT = Mockito.spy(realSUT);
final String argument = "Argument";
doReturn(false).when(spySUT).doSomeStuff(argument);
final boolean result = spySUT.doSomeStuff(argument);
assertFalse(result);
}
An example of using Spy
annotation (note that the same configuration is required as for @Mock
usage – described above) is having
a field of our Test case declared such as:
@Spy
MySystemUnderTest systemUnderTest = new MySystemUnderTest(new Collaborator());
If we want to stub behavior of particular SUT
spy, we need to use either of doXXX
or willXXX
methods family. In our case we called
doReturn(false).when(spySUT).doSomeStuff(argument);
Using Behavior Driven style, we’d accomplish the same using:
willReturn(false).given(spySUT).doSomeStuff(argument);
This way, in case we really need this feature, we can override method behavior of real object.
👩 Are there any limitations when using Mockito
?
Yes. Although there are hacks how to make workarounds (which might lead to tests hard to understand / maintain), Mockito can’t:
- mock final classes and enums
- mock final / static / private methods
Key takeaways
- Mockito is a helper library tailored to perfectly fit
JUnit
tests development - It provides us facilities to configure behavior of our
SUT
’s collaborator(s) - With quite a lightweight syntax, it’s pretty easy to use & configure for own needs
- Basic idea is to mock collaborator objects for a specific behavior and after that test our SUT for given collaborator behavior.
Source code can be checked out from Github
That was all for today! Hope you liked it!