Understanding Mockito ArgumentCaptor using Spring Boot Test Example | JavaInUse



Understanding Mockito ArgumentCaptor using Spring Boot Test Example

Consider a scenario where we are testing a method that depends on a collaborator. This collaborator takes an argument while calling one of its methods.
Now there can be two scenarios-
  • 1. The argument is passed externally to the method we are testing and then used by the collaborator during its own method call
        method(argument arg)
    	{
    	 collaborator.callMethod(arg);
    	}
    	
    To test this method we mock the collaborator and then call the method as follows
    	method(arg1);
    	Mockito.verify(collaborator).callMethod(arg1);
    	
    So here in the test method we have the arg1 instance and hence can be verified
  • 2. The argument being used by the collaborator to make its own method call is not passed externally and but created inside the method being tested
       
        method()
    	{
    	 arg=CreateArgumentInternally();
    	 collaborator.callMethod(arg);
    	}
    	
    To test this method we mock the collaborator and then call the method as follows
        method();
    	
    But how do we verify the collaborator was called with which arguments since we don't have the access to the argument as it was created internally inside the method. This where the Mockito ArgumentCaptor comes into picture. Using the ArgumentCaptor we can get the argument instance created internally and used in the collaborator call and thus we can verify it.
    	
       Mockito.verify(collaborator).callMethod(captor.capture());
       Argument actual = captor.getValue();
       
Lets make use of the code we developed in previous example Spring Boot + JDBC Here service class has dependency on the dao class. We will be writing test cases for the EmployeeServiceImpl class
The project structure is as follows-

We have the service class as follows-
   package com.javainuse.service;

import java.util.List;

import com.javainuse.model.Employee;

public interface EmployeeService {
    void insertEmployeeUsingEmployeeId(String employeeId);
       
	void insertEmployee(Employee emp);

	void insertEmployees(List<Employee> employees);

	void getAllEmployees();

	void getEmployeeById(String empid);

}
   
The ServiceImpl class will be as follows-
   package com.javainuse.service.impl;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.javainuse.dao.EmployeeDao;
import com.javainuse.model.Employee;
import com.javainuse.service.EmployeeService;

@Service
public class EmployeeServiceImpl implements EmployeeService {

	@Autowired
	EmployeeDao employeeDao;

	@Override
	public void insertEmployee(Employee employee) {
		employeeDao.insertEmployee(employee);
	}

	@Override
	public void insertEmployeeUsingEmployeeId(String employeeId) {
		Employee emp = new Employee();
		emp.setEmpId(employeeId);
		emp.setEmpName("testEmp");
		employeeDao.insertEmployee(emp);
	}

	@Override
	public void insertEmployees(List<Employee> employees) {
		employeeDao.insertEmployees(employees);
	}

	public void getAllEmployees() {
		List<Employee> employees = employeeDao.getAllEmployees();
		for (Employee employee : employees) {
			System.out.println(employee.toString());
		}
	}

	@Override
	public void getEmployeeById(String empId) {
		Employee employee = employeeDao.getEmployeeById(empId);
		System.out.println(employee);
	}

}
   
We will now write test cases to test the insertEmployeeUsingEmployeeId(String employeeId) and insertEmployee(Employee emp) method.
package com.javainuse.service.impl;

import static org.junit.Assert.assertEquals;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;

import com.javainuse.dao.EmployeeDao;
import com.javainuse.model.Employee;

@RunWith(MockitoJUnitRunner.class)
public class EmployeeServiceImplTest {

	@Mock
	private EmployeeDao employeeDao;

	@InjectMocks
	private EmployeeServiceImpl employeeServiceImpl = new EmployeeServiceImpl();

	@Test
	public void testEmployee() {
		Employee emp = new Employee();

		employeeServiceImpl.insertEmployee(emp);

	    // here we can verify directly with the emp object we are
		// passing while calling to the service
		Mockito.verify(employeeDao).insertEmployee(emp);
	}

	@Test
	public void testEmployeeWithEmployeeId() {
		ArgumentCaptor<Employee> captor = ArgumentCaptor.forClass(Employee.class);

		Employee emp = new Employee();
		emp.setEmpId("emp1");
		emp.setEmpName("testEmp");

		employeeServiceImpl.insertEmployeeUsingEmployeeId("emp1");

	    // here we dont have instance of employee object(since it is created in
		// the service class
		// and not passed externally) but we want to verify the employee
		// object which was used to call repository. So we use captor.
		// passing while calling to the service
		Mockito.verify(employeeDao).insertEmployee(captor.capture());

		//get the Employee object used by the employeeDao using ArgumentCaptor
		Employee actual = captor.getValue();
		assertEquals(emp.getEmpName(), actual.getEmpName());
		assertEquals(emp.getEmpId(), actual.getEmpId());

	}

}
Download Source Code

Download it -
Mockito ArgumentCaptor Example

See Also

Spring Boot Hello World Application- Create simple controller and jsp view using Maven Spring Boot Tutorial-Spring Data JPA Spring Boot + Simple Security Configuration Pagination using Spring Boot Simple Example Spring Boot + ActiveMQ Hello world Example Spring Boot + Swagger Example Hello World Example Spring Boot + Swagger- Understanding the various Swagger Annotations Spring Boot Main Menu Spring Boot Interview Questions