方案:模拟服务异常以测试控制器中的错误处理
1. Spring Boot 应用代码
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
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) {
// 模拟员工不存在时抛出异常
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);
}
// 全局异常处理
@ExceptionHandler(EmployeeNotFoundException.class)
public ResponseEntity<String> handleEmployeeNotFoundException(EmployeeNotFoundException ex) {
return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
}
}
2. 使用 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); // 初始化 Mock 对象
}
@Test
void testGetEmployee_Success() {
// Arrange: 模拟服务方法返回一个 Employee 对象
when(employeeService.getEmployeeById("1")).thenReturn(new Employee("1", "John Doe"));
// Act: 调用控制器方法
ResponseEntity<Employee> response = employeeController.getEmployee("1");
// Assert: 验证响应是否正确
assertNotNull(response);
assertEquals(200, response.getStatusCodeValue());
assertEquals("John Doe", response.getBody().getName());
// 验证服务方法被调用了一次
verify(employeeService, times(1)).getEmployeeById("1");
}
@Test
void testGetEmployee_ThrowsException() {
// Arrange: 模拟服务方法抛出异常
when(employeeService.getEmployeeById("0")).thenThrow(new EmployeeNotFoundException("Employee not found with id: 0"));
// Act & Assert: 验证异常是否被正确处理
assertThrows(EmployeeNotFoundException.class, () -> {
employeeController.getEmployee("0");
});
// 验证服务方法被调用了一次
verify(employeeService, times(1)).getEmployeeById("0");
}
}
说明:
thenThrow()
的用法:when(employeeService.getEmployeeById("0")).thenThrow(new EmployeeNotFoundException("Employee not found with id: 0"));
这行代码模拟了当 getEmployeeById
方法传入 "0" 时抛出 EmployeeNotFoundException
异常。
单元测试包含两个测试用例:
testGetEmployee_Success
: 测试成功获取员工信息的情况。testGetEmployee_ThrowsException
: 测试员工不存在,服务抛出异常的情况,并验证异常被正确处理。thenThrow()
的优点:
结论:
使用 Mockito 的 thenThrow()
方法,可以有效地测试异常处理逻辑,而无需依赖实际的服务实现。 这使得单元测试更加简洁、可靠,并且易于维护。