Header Ads

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

Powered by Blogger.