# 3.4 系统测试 为确保系统交付质量,我制定并执行了一套覆盖从代码单元到用户场景、从功能正确性到非功能性需求的、多层次、全方位的测试策略。 ## 3.4.1 后端测试 我主要负责后端的单元测试、集成测试和API接口测试,旨在从源头保证服务的稳定、可靠与安全。 ### 1. 单元测试 (Unit Testing) 我坚持“测试驱动开发”(TDD)的理念,使用`JUnit 5`和`Mockito`框架为核心的`Service`层和`Repository`层的公共方法编写了详尽的单元测试。单元测试的目标是隔离验证最小代码单元(一个方法或一个类)的逻辑正确性。 **测试用例示例:`TaskAssignmentService`单元测试** ```java:ems-backend/src/test/java/com/dne/ems/service/TaskAssignmentServiceTest.java @ExtendWith(MockitoExtension.class) class TaskAssignmentServiceTest { @Mock private FeedbackRepository feedbackRepository; @Mock private UserAccountRepository userAccountRepository; @Mock private TaskRepository taskRepository; @Mock private AssignmentRepository assignmentRepository; @InjectMocks private TaskAssignmentServiceImpl taskAssignmentService; @Test void assignTask_Success_ShouldReturnSavedAssignment() { // Arrange: 准备测试数据和模拟行为 Feedback mockFeedback = new Feedback(1L, "Test", "Desc", FeedbackStatus.CONFIRMED, 101L); UserAccount mockAssignee = new UserAccount(202L, "worker", "pass", Role.GRID_WORKER); when(feedbackRepository.findById(1L)).thenReturn(Optional.of(mockFeedback)); when(userAccountRepository.findById(202L)).thenReturn(Optional.of(mockAssignee)); when(taskRepository.save(any(Task.class))).thenAnswer(i -> i.getArgument(0)); when(assignmentRepository.save(any(Assignment.class))).thenAnswer(i -> i.getArgument(0)); // Act: 执行被测试的方法 Assignment result = taskAssignmentService.assignTask(1L, 202L, 303L); // Assert: 验证结果和交互 assertNotNull(result); assertEquals(202L, result.getAssigneeId()); verify(feedbackRepository, times(1)).save(any(Feedback.class)); // 验证Feedback状态是否被更新并保存 assertEquals(FeedbackStatus.ASSIGNED, mockFeedback.getStatus()); } @Test void assignTask_FeedbackNotFound_ShouldThrowException() { // Arrange when(feedbackRepository.findById(99L)).thenReturn(Optional.empty()); // Act & Assert assertThrows(IllegalArgumentException.class, () -> { taskAssignmentService.assignTask(99L, 202L, 303L); }); } } ``` **测试策略说明:** * **Mocking:** 使用`Mockito`框架模拟(Mock)外部依赖(如各个Repository),使得测试可以专注于`Service`层自身的业务逻辑,而不受数据库或文件系统的影响。 * **覆盖度:** 我为每个公共方法都编写了多个测试用例,覆盖了“成功路径”和各种“异常路径”(如输入非法、依赖返回空等),力求达到较高的代码覆盖率和逻辑覆盖率。 ### 2. API接口测试 (API Testing) 我利用`SpringDoc`与`Swagger UI`的无缝集成,以及更专业的API测试工具`Postman`,对所有RESTful API进行了系统性的黑盒测试。 * **测试范围:** 覆盖了用户认证、权限管理、反馈生命周期、任务生命周期等所有核心模块的每一个API端点。 * **测试方法:** 我为每个API编写了一系列测试用例,形成了一个`Postman`测试集(Collection),这使得测试可以被保存、共享和重复执行。 **API测试用例表示例 (扩展):** | 用例ID | 模块 | 接口 | 场景描述 | 输入数据 | 预期HTTP状态 | 预期响应体关键内容 | 结果 | | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | | TC-API-001 | 任务管理 | `POST /api/assignments` | 成功分配任务 | 合法的`feedbackId`, `assigneeId` | `201 Created` | 返回新创建的`assignment`对象JSON | 通过 | | TC-API-002 | 任务管理 | `POST /api/assignments` | **异常**:反馈ID不存在 | `feedbackId: 9999` | `404 Not Found` | `"message": "Feedback with id 9999 not found"` | 通过 | | TC-API-003 | 任务管理 | `POST /api/assignments` | **异常**:指派的用户不是网格员 | `assigneeId`指向一个`ADMIN`角色的用户 | `400 Bad Request` | `"message": "User is not a grid worker"` | 通过 | | TC-API-004 | 任务管理 | `POST /api/assignments` | **异常**:反馈状态不正确 | `feedbackId`指向一个`PENDING`状态的反馈 | `400 Bad Request` | `"message": "Feedback is not in a CONFIRMED state"` | 通过 | | TC-API-005 | 安全 | `POST /api/assignments` | **安全**:无JWT令牌 | `Authorization`头为空 | `401 Unauthorized` | (空或错误提示) | 通过 | | TC-API-006 | 安全 | `POST /api/assignments` | **安全**:使用网格员角色的JWT | `Authorization`头为一个`GRID_WORKER`的JWT | `403 Forbidden` | (空或错误提示) | 通过 | ## 3.4.2 前端测试 我与负责前端的组员紧密协作,进行了全面的前端功能、UI/UX和兼容性测试。 * **手工功能测试:** 我们以用户故事(User Story)为驱动,模拟不同角色的用户(公众、网格员、主管、管理员),完整地执行了所有核心业务流程的端到端场景,确保功能符合需求规格。 * **UI/UX测试:** 仔细检查了界面的布局、色彩、字体、图标和交互动效,确保其在主流浏览器(Chrome, Firefox, Edge)的不同版本和不同屏幕分辨率下(如`1920x1080`, `1366x768`)都能保持良好的一致性、美观度和用户体验。 ## 3.4.3 集成与系统测试 在前后端分别完成各自的测试后,我们将整个系统部署到一台独立的测试服务器上,进行了端到端的集成测试和系统测试。 * **目的:** 验证前后端数据接口的正确性、API调用的顺畅性、以及在真实网络环境下整个系统业务流程的闭环。 * **过程:** 我们共同执行了一套预先设计的系统级测试用例,这些用例模拟了真实世界中的复杂操作序列。例如: 1. 公众用户A提交反馈 -> 主管B审核通过 -> 主管B将任务分配给网格员C -> 网格员C完成任务并提交数据 -> 主管B查看已完成的任务和数据。 2. 并发测试:多个用户同时提交反馈或更新任务,验证后端`synchronized`机制是否有效防止了数据冲突。 * **结果:** 通过严格的集成联调测试,我们发现并修复了若干在单元测试阶段难以暴露的问题(如跨域CORS配置问题、序列化/反序列化日期格式不一致问题、JWT刷新逻辑的边界条件等),最终确保了前后端系统的无缝集成和稳定运行。 ## 3.4.4 非功能性测试 除了功能测试,我还对系统的部分非功能性需求进行了初步的探索性测试。 * **性能测试:** 使用`Apache JMeter`工具,对核心的登录和查询类API进行了简单的压力测试。模拟20个并发用户持续请求,观察到API的平均响应时间仍在200ms以内,CPU和内存占用率处于合理范围,初步证明系统具备应对一定并发访问的能力。 * **安全测试:** * **权限测试:** 严格测试了不同角色的用户访问未授权API的情况,验证系统是否能正确返回`403 Forbidden`。 * **输入验证:** 尝试提交包含恶意脚本(XSS)或SQL注入(虽然我们不是SQL数据库,但原理相通)的表单数据,验证后端是否有充分的输入清理和验证机制。