A Guide to Mocking With Mockito
If you're thinking about trying Mockito out for unit testing, this article provides a comprehensive guide to injecting mocks and mocking methods, including void methods.
Join the DZone community and get the full member experience.
Join For FreeMost of the classes we come across have dependencies, and oftentimes, methods delegate some work to other methods in other classes. These classes are our dependencies. When unit testing such methods, if we only use JUnit, our tests will also depend on those methods as well. We want the unit tests to be independent of all other dependencies.
- Say we want to test the method
addCustomer
in theCustomerService
class, and within thisaddCustomer
method, the save method of theCustomerDao
class is invoked. We don’t want to call the real implementation of theCustomerDao
save()
method for a few reasons:- We only want to test the logic inside the
addCustomer()
in isolation. - We may not yet have implemented it.
- We don’t want the unit test of the
addCustomer()
fail if there is a defect in thesave()
method in theCustomerDao
.
- We only want to test the logic inside the
- So we should somehow mock the behavior of the dependencies. This is where mocking frameworks come into play.
- Mockito is what I use for just this, and in this post, we’ll see how to effectively use Mockito to mock those dependencies.
If you are new to unit testing with JUnit, please check out an earlier post of mine on How to write great unit tests with JUnit
What Is Mockito?
Mockito is a mocking framework that tastes really good. It lets you write beautiful tests with a clean & simple API. Mockito doesn’t give you hangover because the tests are very readable and they produce clean verification errors.
— “Mockito.” Mockito Framework Site. N.p., n.d. Web. 28 Apr. 2017.
Injecting Mocks With Mockito
So, going back to the example above, how do we mock out the dependency using Mockito? Well, we could inject a mock to the class under test instead of the real implementation while we run our tests!
Let’s look at an example of a class under test which has a dependency on CustomerDao
:
public class CustomerService {
@Inject
private CustomerDao customerDao;
public boolean addCustomer(Customer customer){
if(customerDao.exists(customer.getPhone())){
return false;
}
return customerDao.save(customer);
}
public CustomerDao getCustomerDao() {
return customerDao;
}
public void setCustomerDao(CustomerDao customerDao) {
this.customerDao = customerDao;
}
}
The following is the test that mocks the dependency using Mockito:
public class CustomerServiceTest {
@Mock
private CustomerDao daoMock;
@InjectMocks
private CustomerService service;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
@Test
public void test() {
//assertion here
}
}
Let’s look at the role of the annotations in the above example.
@Mock
will create a mock implementation for theCustomerDao
@InjectMocks
will inject the mocks marked with@Mock
to this instance when it is created.- So when or where are these instances created? Well, it is done in this line, which resides in the setUp method:
MockitoAnnotations.initMocks(this);
- So these instances would be created at the start of every test method of this test class.
Mocking Methods With Mockito
Great! Now we have successfully created and injected the mock, and now we should tell the mock how to behave when certain methods are called on it.
The when
then
pattern:
- We do this in each of the test methods. The following line of code tells the Mockito framework that we want the
save()
method of the mock DAO instance to return true when passed in a certain customer instance.
when(dao.save(customer)).thenReturn(true);
when
is a static method of the Mockito class, and it returns anOngoingStubbing<T>
(T
is the return type of the method that we are mocking — in this case, it isboolean
).- So if we just extract that out to get ahold of the stub, it looks like this:
OngoingStubbing<Boolean> stub = when(dao.save(customer));
- The following are some of the methods that we can call on this
stub
thenReturn(returnValue)
thenThrow(exception)
thenCallRealMethod()
thenAnswer()
- this could be used to set up smarter stubs and also mock the behavior of void methods as well (see How to mock void method behavior).
- Simply putting this all in one line again:
when(dao.save(customer)).thenReturn(true);
- Do we really need to pass in an actual customer object to the save method here? No, we could use matchers like the following:
when(dao.save(any(Customer.class))).thenReturn(true);
- However, when there are multiple parameters to a method, we cannot mix matchers and actual objects. For example, we cannot do the following:
Mockito.when(mapper.map(any(), "test")).thenReturn(new Something());
This would compile without a complaint but would fail during runtime with an error saying:matchers can't be mixed with actual values in the list of arguments to a single
method. - We either have to use matchers for all parameters or should pass in real values or objects.
Mock behavior of dependencies using Mockito.when
:
package com.tdd;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.*;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
public class CustomerServiceTest {
@Mock
private CustomerDao daoMock;
@InjectMocks
private CustomerService service;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
@Test
public void testAddCustomer_returnsNewCustomer() {
when(daoMock.save(any(Customer.class))).thenReturn(new Customer());
Customer customer = new Customer();
assertThat(service.addCustomer(customer), is(notNullValue()));
}
//Using Answer to set an id to the customer which is passed in as a parameter to the mock method.
@Test
public void testAddCustomer_returnsNewCustomerWithId() {
when(daoMock.save(any(Customer.class))).thenAnswer(new Answer<Customer>() {
@Override
public Customer answer(InvocationOnMock invocation) throws Throwable {
Object[] arguments = invocation.getArguments();
if (arguments != null && arguments.length > 0 && arguments[0] != null){
Customer customer = (Customer) arguments[0];
customer.setId(1);
return customer;
}
return null;
}
});
Customer customer = new Customer();
assertThat(service.addCustomer(customer), is(notNullValue()));
}
//Throwing an exception from the mocked method
@Test(expected = RuntimeException.class)
public void testAddCustomer_throwsException() {
when(daoMock.save(any(Customer.class))).thenThrow(RuntimeException.class);
Customer customer = new Customer();
service.addCustomer(customer);//
}
}
Mocking Void Methods With Mockito
doAnswer
: If we want our mocked void method to do something (mock the behavior despite being void).doThrow
: Then there isMockito.doThrow()
if you want to throw an exception from the mocked void method.
The following is an example of how to use it. Bear in mind, it isn't an ideal use case, but I wanted to illustrate the basic usage:
@Test
public void testUpdate() {
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
Object[] arguments = invocation.getArguments();
if (arguments != null && arguments.length > 1 && arguments[0] != null && arguments[1] != null) {
Customer customer = (Customer) arguments[0];
String email = (String) arguments[1];
customer.setEmail(email);
}
return null;
}
}).when(daoMock).updateEmail(any(Customer.class), any(String.class));
// calling the method under test
Customer customer = service.changeEmail("old@test.com", "new@test.com");
//some asserts
assertThat(customer, is(notNullValue()));
assertThat(customer.getEmail(), is(equalTo("new@test.com")));
}
@Test(expected = RuntimeException.class)
public void testUpdate_throwsException() {
doThrow(RuntimeException.class).when(daoMock).updateEmail(any(Customer.class), any(String.class));
// calling the method under test
Customer customer = service.changeEmail("old@test.com", "new@test.com");
}
}
The Two Ways of Testing Void Methods With Mockito
Methods with return values can be tested by asserting the returned value, but how do we test void methods? The void method that you want to test could either be calling other methods to get things done, processing the input parameters, or maybe generating some values or all of it. With Mockito, you can test all of the above scenarios.
Verify With Mockito
A great thing about mocking is that we can verify that certain methods have been called on those mock objects during test execution — in addition to or in place of assertions — when the method under test is void.
- There are two overloaded verify methods.
- One that accepts only the mock object — we can use this if the method is supposed to be invoked only once.
- The other accepts the mock and a
VerificationMode
— there are quite a few methods in the Mockito class that provide some useful verificationModes:times(int wantedNumberOfInvocations)
atLeast( int wantedNumberOfInvocations )
atMost( int wantedNumberOfInvocations )
calls( int wantedNumberOfInvocations )
only( int wantedNumberOfInvocations )
atLeastOnce()
never()
Mockito.verify
:
package com.tdd;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.*;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
public class CustomerServiceTest {
@Mock
private CustomerDao daoMock;
@InjectMocks
private CustomerService service;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
@Test
public void test() {
when(daoMock.save(any(Customer.class))).thenReturn(true);
Customer customer=new Customer();
assertThat(service.addCustomer(customer), is(true));
//verify that the save method has been invoked
verify(daoMock).save(any(Customer.class));
//the above is similar to : verify(daoMock, times(1)).save(any(Customer.class));
//verify that the exists method is invoked one time
verify(daoMock, times(1)).exists(anyString());
//verify that the delete method has never been invoked
verify(daoMock, never()).delete(any(Customer.class));
}
}
Capture Arguments
Another cool feature is the ArgumentCaptor
, which allows us to capture any arguments passed into the mocked or spied methods.
Mockito.ArgumentCaptor
:
package com.service;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.verify;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import com.dao.CustomerDao;
import com.entity.Customer;
public class CustomerServiceTest {
@Mock
private CustomerDao doaMock;
@InjectMocks
private CustomerService service;
@Captor
private ArgumentCaptor<Customer> customerArgument;
public CustomerServiceTest() {
MockitoAnnotations.initMocks(this);
}
@Test
public void testRegister() {
//Requirement: we want to register a new customer. Every new customer should be assigned a random token before saving in the database.
service.register(new Customer());
//captures the argument which was passed in to save method.
verify(doaMock).save(customerArgument.capture());
//make sure a token is assigned by the register method before saving.
assertThat(customerArgument.getValue().getToken(), is(notNullValue()));
}
}
I Spy: Spying With Mockito
Why spy?
- Sometimes we need to call real methods of a dependency but still want to verify or track interactions with that dependency. This is where we would use a spy.
- When a field is annotated with
@Spy
, Mockito will create a wrapper around an actual instance of that object and, therefore, we can call a real implementation and also verify interactions at the same time. - Some of the behavior of a spy could be mocked if needed.
- In the example below, the dependency behavior is not mocked, but its interactions are verified.
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.*;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
public class CustomerServiceTestV2 {
@Spy
private CustomerDaoImpl daoSpy;
@InjectMocks
private CustomerService service;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
@Test
public void test() {
Customer customer = new Customer();
assertThat(service.addCustomer(customer), is(false));
verify(daoSpy).save(any(Customer.class));
verify(daoSpy, times(1)).exists(anyString());
verify(daoSpy, never()).delete(any(Customer.class));
}
}
Head over here to get the example source code given in this tutorial.
That’s it on this post! Please check out the below websites for more cool features, best practices, and guidelines on Mockito.
Published at DZone with permission of Dilini Rajapaksha. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments