/** * 用户管理模块集成测试 * * 功能描述: * - 测试用户管理模块的完整业务流程 * - 测试控制器与服务的集成 * - 测试真实的HTTP请求处理 * - 测试端到端的业务场景 * * 职责分离: * - 集成测试覆盖完整的业务流程 * - 测试模块间的协作和数据流 * - 验证真实环境下的功能表现 * * 最近修改: * - 2026-01-07: 代码规范优化 - 创建完整的集成测试覆盖 (修改者: moyin) * * @author moyin * @version 1.0.1 * @since 2026-01-07 * @lastModified 2026-01-07 */ import { Test, TestingModule } from '@nestjs/testing'; import { INestApplication } from '@nestjs/common'; import { UserStatusController } from './user_status.controller'; import { UserManagementService } from './user_management.service'; import { AdminService } from '../admin/admin.service'; import { AdminGuard } from '../admin/guards/admin.guard'; import { UserStatusDto, BatchUserStatusDto } from './user_status.dto'; import { UserStatus } from './user_status.enum'; import { BATCH_OPERATION, ERROR_CODES, MESSAGES } from './user_mgmt.constants'; describe('UserManagement Integration', () => { let app: INestApplication; let controller: UserStatusController; let userManagementService: UserManagementService; let mockAdminService: jest.Mocked; beforeAll(async () => { // Create mock AdminService const mockAdminServiceProvider = { updateUserStatus: jest.fn(), batchUpdateUserStatus: jest.fn(), getUserStatusStats: jest.fn(), }; const moduleFixture: TestingModule = await Test.createTestingModule({ controllers: [UserStatusController], providers: [ UserManagementService, { provide: AdminService, useValue: mockAdminServiceProvider, }, ], }) .overrideGuard(AdminGuard) .useValue({ canActivate: jest.fn(() => true) }) .compile(); app = moduleFixture.createNestApplication(); await app.init(); controller = moduleFixture.get(UserStatusController); userManagementService = moduleFixture.get(UserManagementService); mockAdminService = moduleFixture.get(AdminService); }); afterAll(async () => { await app.close(); }); beforeEach(() => { jest.clearAllMocks(); }); describe('Complete User Status Management Flow', () => { it('should handle complete user status update workflow', async () => { // Arrange const userId = '123'; const userStatusDto: UserStatusDto = { status: UserStatus.LOCKED, reason: '用户违反社区规定' }; const mockUpdateResult = { success: true, data: { user: { id: '123', username: 'testuser', nickname: '测试用户', status: UserStatus.LOCKED, status_description: '已锁定', updated_at: new Date('2026-01-07T10:00:00.000Z') }, reason: '用户违反社区规定' }, message: '用户状态修改成功' }; mockAdminService.updateUserStatus.mockResolvedValue(mockUpdateResult); // Act - Controller calls Service, Service calls AdminService const result = await controller.updateUserStatus(userId, userStatusDto); // Assert - Verify complete integration expect(result).toEqual(mockUpdateResult); expect(mockAdminService.updateUserStatus).toHaveBeenCalledWith(BigInt(123), userStatusDto); expect(result.data.user.status).toBe(UserStatus.LOCKED); expect(result.data.reason).toBe('用户违反社区规定'); }); it('should handle complete batch update workflow', async () => { // Arrange const batchUserStatusDto: BatchUserStatusDto = { userIds: ['1', '2', '3'], status: UserStatus.BANNED, reason: '批量处理违规用户' }; const mockBatchResult = { success: true, data: { result: { success_users: [ { id: '1', username: 'user1', nickname: '用户1', status: UserStatus.BANNED, status_description: '已封禁', updated_at: new Date() }, { id: '2', username: 'user2', nickname: '用户2', status: UserStatus.BANNED, status_description: '已封禁', updated_at: new Date() } ], failed_users: [ { user_id: '3', error: '用户不存在' } ], success_count: 2, failed_count: 1, total_count: 3 }, reason: '批量处理违规用户' }, message: '批量用户状态修改完成' }; mockAdminService.batchUpdateUserStatus.mockResolvedValue(mockBatchResult); // Act - Complete batch workflow const result = await controller.batchUpdateUserStatus(batchUserStatusDto); // Assert - Verify batch integration expect(result).toEqual(mockBatchResult); expect(result.data.result.success_count).toBe(2); expect(result.data.result.failed_count).toBe(1); expect(mockAdminService.batchUpdateUserStatus).toHaveBeenCalledWith(batchUserStatusDto); }); it('should handle complete statistics workflow', async () => { // Arrange const mockStatsResult = { success: true, data: { stats: { active: 1000, inactive: 200, locked: 50, banned: 25, deleted: 10, pending: 30, total: 1315 }, timestamp: '2026-01-07T10:00:00.000Z' }, message: '用户状态统计获取成功' }; mockAdminService.getUserStatusStats.mockResolvedValue(mockStatsResult); // Act - Complete statistics workflow const result = await controller.getUserStatusStats(); // Assert - Verify statistics integration expect(result).toEqual(mockStatsResult); expect(result.data.stats.total).toBe(1315); expect(mockAdminService.getUserStatusStats).toHaveBeenCalledTimes(1); }); }); describe('Business Logic Integration', () => { it('should enforce batch operation limits through service layer', async () => { // Arrange - Create request exceeding limits const userIds = Array.from({ length: BATCH_OPERATION.MAX_USER_COUNT + 1 }, (_, i) => i.toString()); const batchUserStatusDto: BatchUserStatusDto = { userIds, status: UserStatus.LOCKED, reason: '超限测试' }; // Act - Service should reject before calling AdminService const result = await userManagementService.batchUpdateUserStatus(batchUserStatusDto); // Assert - Verify business rule enforcement expect(result.success).toBe(false); expect(result.message).toBe(MESSAGES.BATCH_OPERATION_LIMIT_ERROR); expect(result.error_code).toBe(ERROR_CODES.BATCH_OPERATION_LIMIT_EXCEEDED); expect(mockAdminService.batchUpdateUserStatus).not.toHaveBeenCalled(); }); it('should handle user status history integration', async () => { // Arrange const userId = BigInt(456); const limit = 10; // Act - Test history functionality (currently mock implementation) const result = await userManagementService.getUserStatusHistory(userId, limit); // Assert - Verify history integration expect(result.success).toBe(true); expect(result.data.user_id).toBe('456'); expect(result.data.history).toEqual([]); expect(result.data.total_count).toBe(0); expect(result.message).toContain('状态变更历史获取成功'); }); }); describe('Error Handling Integration', () => { it('should handle service errors through complete stack', async () => { // Arrange const userId = '999'; const userStatusDto: UserStatusDto = { status: UserStatus.ACTIVE, reason: '测试错误处理' }; const mockErrorResult = { success: false, message: '用户不存在', error_code: 'USER_NOT_FOUND' }; mockAdminService.updateUserStatus.mockResolvedValue(mockErrorResult); // Act - Error propagation through layers const result = await controller.updateUserStatus(userId, userStatusDto); // Assert - Verify error handling integration expect(result.success).toBe(false); expect(result.message).toBe('用户不存在'); expect(result.error_code).toBe('USER_NOT_FOUND'); }); it('should handle batch operation partial failures', async () => { // Arrange const batchUserStatusDto: BatchUserStatusDto = { userIds: ['1', '2', '999', '888'], status: UserStatus.ACTIVE, reason: '批量激活测试' }; const mockPartialFailureResult = { success: true, data: { result: { success_users: [ { id: '1', username: 'user1', nickname: '用户1', status: UserStatus.ACTIVE, status_description: '正常', updated_at: new Date() }, { id: '2', username: 'user2', nickname: '用户2', status: UserStatus.ACTIVE, status_description: '正常', updated_at: new Date() } ], failed_users: [ { user_id: '999', error: '用户不存在' }, { user_id: '888', error: '用户状态无法修改' } ], success_count: 2, failed_count: 2, total_count: 4 }, reason: '批量激活测试' }, message: '批量用户状态修改完成' }; mockAdminService.batchUpdateUserStatus.mockResolvedValue(mockPartialFailureResult); // Act - Handle partial failures const result = await controller.batchUpdateUserStatus(batchUserStatusDto); // Assert - Verify partial failure handling expect(result.success).toBe(true); expect(result.data.result.success_count).toBe(2); expect(result.data.result.failed_count).toBe(2); expect(result.data.result.failed_users).toHaveLength(2); }); it('should handle statistics service failures', async () => { // Arrange const mockStatsError = { success: false, message: '数据库连接失败', error_code: 'DATABASE_CONNECTION_ERROR' }; mockAdminService.getUserStatusStats.mockResolvedValue(mockStatsError); // Act - Handle statistics errors const result = await controller.getUserStatusStats(); // Assert - Verify error propagation expect(result.success).toBe(false); expect(result.message).toBe('数据库连接失败'); expect(result.error_code).toBe('DATABASE_CONNECTION_ERROR'); }); }); describe('Data Flow Integration', () => { it('should maintain data consistency through all layers', async () => { // Arrange const userId = '789'; const userStatusDto: UserStatusDto = { status: UserStatus.INACTIVE, reason: '长期未活跃' }; const mockResult = { success: true, data: { user: { id: '789', username: 'inactive_user', nickname: '非活跃用户', status: UserStatus.INACTIVE, status_description: '非活跃', updated_at: new Date('2026-01-07T10:00:00.000Z') }, reason: '长期未活跃' }, message: '用户状态修改成功' }; mockAdminService.updateUserStatus.mockResolvedValue(mockResult); // Act - Data flows through Controller -> Service -> AdminService const result = await controller.updateUserStatus(userId, userStatusDto); // Assert - Verify data consistency expect(result.data.user.id).toBe(userId); expect(result.data.user.status).toBe(userStatusDto.status); expect(result.data.reason).toBe(userStatusDto.reason); expect(mockAdminService.updateUserStatus).toHaveBeenCalledWith( BigInt(789), expect.objectContaining({ status: UserStatus.INACTIVE, reason: '长期未活跃' }) ); }); it('should handle BigInt conversion correctly in data flow', async () => { // Arrange - Test large number handling const largeUserId = '9007199254740991'; const userStatusDto: UserStatusDto = { status: UserStatus.PENDING, reason: '大数字ID测试' }; const mockResult = { success: true, data: { user: { id: largeUserId, username: 'large_id_user', nickname: '大ID用户', status: UserStatus.PENDING, status_description: '待处理', updated_at: new Date() }, reason: '大数字ID测试' }, message: '用户状态修改成功' }; mockAdminService.updateUserStatus.mockResolvedValue(mockResult); // Act - Test BigInt conversion in data flow const result = await controller.updateUserStatus(largeUserId, userStatusDto); // Assert - Verify BigInt handling expect(result.data.user.id).toBe(largeUserId); expect(mockAdminService.updateUserStatus).toHaveBeenCalledWith( BigInt('9007199254740991'), userStatusDto ); }); }); describe('Performance Integration', () => { it('should handle maximum allowed batch size efficiently', async () => { // Arrange - Test with maximum allowed batch size const userIds = Array.from({ length: BATCH_OPERATION.MAX_USER_COUNT }, (_, i) => `user_${i}`); const batchUserStatusDto: BatchUserStatusDto = { userIds, status: UserStatus.ACTIVE, reason: '性能测试' }; const mockResult = { success: true, data: { result: { success_users: userIds.map(id => ({ id, username: `user_${id}`, nickname: `用户_${id}`, status: UserStatus.ACTIVE, status_description: '正常', updated_at: new Date() })), failed_users: [], success_count: userIds.length, failed_count: 0, total_count: userIds.length }, reason: '性能测试' }, message: '批量用户状态修改完成' }; mockAdminService.batchUpdateUserStatus.mockResolvedValue(mockResult); // Act - Process maximum batch size const startTime = Date.now(); const result = await controller.batchUpdateUserStatus(batchUserStatusDto); const endTime = Date.now(); // Assert - Verify performance and correctness expect(result.success).toBe(true); expect(result.data.result.total_count).toBe(BATCH_OPERATION.MAX_USER_COUNT); expect(endTime - startTime).toBeLessThan(1000); // Should complete within 1 second }); }); });