Scenario: Mocking a Service to Throw an Exception for Testing Error Handling in a Controller
1. Spring Boot Application Code
Employee.java
package com.example.demo.model;
public class Employee {
private String id;
private String name;
// Constructors, Getters, and Setters
public Employee(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
EmployeeNotFoundException.java (Custom Exception)
package com.example.demo.exception;
public class EmployeeNotFoundException extends RuntimeException {
public EmployeeNotFoundException(String message) {
super(message);
}
}
EmployeeService.java
package com.example.demo.service;
import com.example.demo.exception.EmployeeNotFoundException;
import com.example.demo.model.Employee;
import org.springframework.stereotype.Service;
@Service
public class EmployeeService {
public Employee getEmployeeById(String id) {
// Simulating an exception when employee is not found
if ("0".equals(id)) {
throw new EmployeeNotFoundException("Employee not found with id: " + id);
}
return new Employee(id, "John Doe");
}
}
EmployeeController.java
package com.example.demo.controller;
import com.example.demo.exception.EmployeeNotFoundException;
import com.example.demo.model.Employee;
import com.example.demo.service.EmployeeService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/employees")
public class EmployeeController {
private final EmployeeService employeeService;
public EmployeeController(EmployeeService employeeService) {
this.employeeService = employeeService;
}
@GetMapping("/{id}")
public ResponseEntity<Employee> getEmployee(@PathVariable String id) {
Employee employee = employeeService.getEmployeeById(id);
return ResponseEntity.ok(employee);
}
// Global Exception Handling
@ExceptionHandler(EmployeeNotFoundException.class)
public ResponseEntity<String> handleEmployeeNotFoundException(EmployeeNotFoundException ex) {
return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
}
}
- Unit Test Using thenThrow() EmployeeControllerTest.java
package com.example.demo.controller;
import com.example.demo.exception.EmployeeNotFoundException;
import com.example.demo.model.Employee;
import com.example.demo.service.EmployeeService;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.http.ResponseEntity;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
class EmployeeControllerTest {
@Mock
private EmployeeService employeeService;
@InjectMocks
private EmployeeController employeeController;
public EmployeeControllerTest() {
MockitoAnnotations.openMocks(this); // Initialize mocks
}
@Test
void testGetEmployee_Success() {
// Arrange: Stub service method to return an Employee
when(employeeService.getEmployeeById("1")).thenReturn(new Employee("1", "John Doe"));
// Act: Call the controller method
ResponseEntity<Employee> response = employeeController.getEmployee("1");
// Assert: Verify response is correct
assertNotNull(response);
assertEquals(200, response.getStatusCodeValue());
assertEquals("John Doe", response.getBody().getName());
// Verify the service method was called once
verify(employeeService, times(1)).getEmployeeById("1");
}
@Test
void testGetEmployee_ThrowsException() {
// Arrange: Stub the service method to throw an exception
when(employeeService.getEmployeeById("0")).thenThrow(new EmployeeNotFoundException("Employee not found with id: 0"));
// Act & Assert: Verify that the exception is handled correctly
Exception exception = assertThrows(EmployeeNotFoundException.class, () -> {
employeeController.getEmployee("0");
});
assertEquals("Employee not found with id: 0", exception.getMessage());
// Verify the service method was called once
verify(employeeService, times(1)).getEmployeeById("0");
}
}
Explanation
Using thenThrow()
when(employeeService.getEmployeeById("0")).thenThrow(new EmployeeNotFoundException("Employee not found with id: 0"))
This stubs the service method to throw EmployeeNotFoundException when called with "0".
Unit Test Steps
- First Test Case (testGetEmployee_Success)
Mocks a successful response using thenReturn().
Calls the controller and asserts the response.
- Second Test Case (testGetEmployee_ThrowsException)
Uses thenThrow() to simulate an exception.
Calls the controller method and asserts that the exception is thrown.
Uses assertThrows() to verify exception handling.
Advantages of thenThrow()
Simulates real-world error handling without modifying the actual service.
Helps in testing exception scenarios like database errors, missing data, API failures, etc.
Ensures that the application responds correctly when errors occur.
Conclusion
Using Mockito’s thenThrow(), you can efficiently test exception handling scenarios in a Spring Boot application without executing the actual logic.
Top comments (0)