Skip to content
thesarfo

Concept

Testing: Service Layer

Mocking a repository dependency with Mockito's @Mock and @InjectMocks to unit test a service in isolation.

views 0

Spring’s controller/service/repository layering means the repository talks to the DB, and the service talks to the repository. To test the service layer in isolation, we need to fake its repository dependency — that’s mocking, and Mockito makes it possible.

Mocking dependencies with Mockito

  • Mockito.mock() — creates a mock object of a given class/interface; the simplest way to mock.
  • @Mock — also mocks an object, but is especially useful when the mock is used in multiple places, since it avoids repeated mock() calls and makes the code more readable (and gives the mock a name that shows up in error messages).
  • @InjectMocks — injects mocked objects into another object under test. It creates an instance of the class and injects any fields marked @Mock into it.
@ExtendWith(MockitoExtension.class)
public class EmployeeServiceTest {
@Mock
private EmployeeRepository employeeRepository;
@InjectMocks
private EmployeeServiceImpl employeeService;
}

This mocks EmployeeServiceTest’s dependency and injects employeeRepository into employeeService. Mockito also has a BDDMockito class for BDD-style given(...).willReturn(...) assertions. A full service-layer test class:

@ExtendWith(MockitoExtension.class)
class EmployeeServiceImplTest {
@Mock
private EmployeeRepository employeeRepository;
@InjectMocks
private EmployeeServiceImpl employeeService;
private Employee employee;
@BeforeEach
public void setup() {
employee = Employee.builder()
.id(1L)
.firstName("Ernest")
.lastName("Sarfo")
.email("sarfo@gmail.com")
.build();
}
@DisplayName("Unit test for saveEmployee method")
@Test
void givenEmployeeObject_whenSaveEmployee_thenReturnEmployeeObject() {
given(employeeRepository.findByEmail(employee.getEmail()))
.willReturn(Optional.empty());
given(employeeRepository.save(employee)).willReturn(employee);
Employee savedEmployee = employeeService.saveEmployee(employee);
assertThat(savedEmployee).isNotNull();
}
@DisplayName("Unit test for saveEmployee method which throws exception")
@Test
void givenExistingEmail_whenSaveEmployee_thenThrowsException() {
given(employeeRepository.findByEmail(employee.getEmail()))
.willReturn(Optional.of(employee));
assertThrows(ResourceNotFoundException.class, () -> employeeService.saveEmployee(employee));
verify(employeeRepository, never()).save(any(Employee.class));
}
@DisplayName("Unit test for getAllEmployeesMethod")
@Test
void givenEmployeeList_whenGetAllEmployees_thenReturnEmployees() {
Employee employee1 = Employee.builder()
.id(2L)
.firstName("Tony")
.lastName("Stark")
.email("stark@gmail.com")
.build();
given(employeeRepository.findAll()).willReturn(List.of(employee, employee1));
List<Employee> employees = employeeService.getAllEmployees();
assertThat(employees).isNotNull();
assertThat(employees).hasSize(2);
}
@DisplayName("Unit test for getAllEmployeesMethod (negative scenario)")
@Test
void givenEmptyEmployeeList_whenGetAllEmployees_thenReturnEmptyEmployeeList() {
given(employeeRepository.findAll()).willReturn(Collections.emptyList());
List<Employee> employees = employeeService.getAllEmployees();
assertThat(employees).isEmpty();
}
@DisplayName("Unit test for get employee by id method")
@Test
void givenEmployeeId_whenFindById_thenReturnEmployeeObject() {
given(employeeRepository.findById(1L)).willReturn(Optional.of(employee));
Optional<Employee> savedEmployee = employeeService.getEmployeeById(1L);
assertThat(savedEmployee).isNotNull();
assertThat(savedEmployee.get().getId()).isEqualTo(1L);
}
@DisplayName("Unit test for update employee method")
@Test
void givenEmployeeObject_whenUpdateEmployee_thenReturnUpdatedEmployee() {
given(employeeRepository.save(employee)).willReturn(employee);
employee.setEmail("travis@gmailcom");
employee.setFirstName("travis");
employee.setLastName("scott");
Employee updatedEmployee = employeeService.updateEmployee(employee);
assertThat(updatedEmployee).isNotNull();
assertThat(updatedEmployee.getFirstName()).isEqualTo("travis");
}
@DisplayName("Unit test for delete employee method")
@Test
void givenEmployee_whenDeleteEmployee_thenReturnNothing() {
long employeeId = 1L;
willDoNothing().given(employeeRepository).deleteById(employeeId);
employeeService.deleteEmployee(employeeId);
verify(employeeRepository, times(1)).deleteById(employeeId);
}
}