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().
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.
Learning by example:
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-
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);
}
}
Reference : http://www.javainuse.com/java/mockSpy
No comments