Difference between Spy and Mock in Mockito | JavaInUse



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 Spy

What 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