Difference between Spy and Mock in Mockito
Overview
In Unit Test cases we can mock the object to be tested. This mocking is usually done using mock. But in scenarios mocking of object using spy is more beneficial. We generally use mock when we have to completely mock the object behavior while using spy we will be spying or stubbing specific methods of it. So mock achieves complete mocking while spy achieves partial mocking(Partial mocking can also be achieved using mock thenCallRealMethod(), when to use spy and thenCallRealMethod is covered in next tutorial.) . For Example, if there is a object with 3 methods such that first two methods are implemented and third method calls an external third party API and you have a test where you want to call all the three methods. Then if using Mock we will have to mock all the three methods. If we use Spy we will not mock all three but only the third method which is a call to an external API.Lets Begin
We will implement the above mentioned scenario of an object having three method calls out of which one method calls an external third party API which we always have to mock. We will first implement this scenario using Mock and then later using Spy. We will now create the EmployeePaymentService class. It has three methods-- getNoOfWorkingDays- Method call to get number of working days of an employee. All logic for this is implemented in this method itself.
- getSalaryPerDay-Method call to get number of daily salary of an employee. All logic for this is implemented in this method itself.
- processPay- Method to calculate the total monthly salary of an employee using his working days and daily salary. This logic is not implemented in the method but a third party API is called which returns the calculated salary.
package com.javainuse.service; public class EmployeePaymentService { /** * @param empId employee id of Employee. * @return number of days the employee has worked. */ public int getNoOfWorkingDays(String empId) { // default value int noOfWorkingDays = 0; // code for getting number of working Days. All logic for this is implemented //in this method itself noOfWorkingDays = 25; return noOfWorkingDays; } /** * @param empId employee id of Employee. * @return salary per day of the employee. */ public int getSalaryPerDay(String empId) { // default value int salaryPerDay = 0; // code for getting salary per day. All logic for this is implemented //in this method itself. salaryPerDay = 1000; return salaryPerDay; } /** * This method is not calculated here but a third party method is called * * @param empId * @param empWrkingDays * @param empSalaryPerDay * @return */ public int processPay(String empId, int empWrkingDays, int empSalaryPerDay) { // code for processing is not done internally here, but a third party // external API call is made. //third party API call // return thirdparty.getSalaryThirdPartyCall(empId,empWrkingDays,empSalaryPerDay); // returning some default value return 20000; } }
Mockito Mock Example
We will completely mock the EmployeePaymentService class using Mock as follows-
package com.javainuse.service; import org.testng.Assert; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.when; public class EmployeePaymentServiceTest_mock { private int testWrkingDays=25; private int testSalaryPerDay=1000; private int testSalary=25000; private String empId="emp100"; //Mock class instance using mock @Mock private EmployeePaymentService employeePaymentService; /** * Setup before test. */ @BeforeMethod public void beforeMethod() { MockitoAnnotations.initMocks(this); } @Test public void testGetSalary() { //Tell mockito to mock all the three methods when(employeePaymentService.getNoOfWorkingDays(anyString())).thenReturn(testWrkingDays); when(employeePaymentService.getSalaryPerDay(anyString())).thenReturn(testSalaryPerDay); when(employeePaymentService.processPay(anyString(), anyInt(), anyInt())).thenReturn(testSalary); //Mock call int returnedWrkingDays=employeePaymentService.getNoOfWorkingDays(empId); Assert.assertEquals(returnedWrkingDays, testWrkingDays); //Mock call int returnedSalaryPerDay=employeePaymentService.getSalaryPerDay(empId); Assert.assertEquals(returnedSalaryPerDay, testSalaryPerDay); //Mock call int returnedSalary=employeePaymentService.processPay(empId,testWrkingDays,testSalaryPerDay); Assert.assertEquals(returnedSalary, testSalary); } }
Mockito Spy Example
We will partially mock the EmployeePaymentService class using Spy as follows-
package com.javainuse.service; import org.testng.Assert; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import org.mockito.MockitoAnnotations; import org.mockito.Spy; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.when; public class EmployeePaymentServiceTest_spy { private int testWrkingDays = 25; private int testSalaryPerDay = 1000; private int testSalary = 25000; private String empId = "emp100"; //Mock class instance using Spy @Spy private EmployeePaymentService employeePaymentService; /** * Setup before test. */ @BeforeMethod public void beforeMethod() { employeePaymentService = new EmployeePaymentService(); MockitoAnnotations.initMocks(this); } @Test public void testGetSalary() { //Tell mockito to mock only the processPay Method when(employeePaymentService.processPay(anyString(), anyInt(), anyInt())).thenReturn(testSalary); //Actual call made int returnedWrkingDays = employeePaymentService.getNoOfWorkingDays(empId); Assert.assertEquals(returnedWrkingDays, testWrkingDays); //Actual call made int returnedSalaryPerDay = employeePaymentService.getSalaryPerDay(empId); Assert.assertEquals(returnedSalaryPerDay, testSalaryPerDay); //Mock call int returnedSalary = employeePaymentService.processPay(empId, testWrkingDays, testSalaryPerDay); Assert.assertEquals(returnedSalary, testSalary); } }
Download Source Code
Download it - Java Mockito using Mock and SpyWhat Next?
The next chapter explains the difference between Spy and thenCallRealMethod.See Also
Using Java Reflections API to map Object Elements Difference between Mock thenCallRealMethod() and Spy in Mockito Checking the specified class contains a field matching the specified name using Java Reflections Getting Started with JMS Messaging- ActiveMQ Hello World Tutorial Getting Name of Current Method inside a method in Java Per4j tutorial: Getting started with Per4j