Files
whale-town-end/src/business/user_mgmt/user_mgmt.integration.spec.ts
moyin 5f662ef091 feat: 完善管理员系统和用户管理模块
- 更新管理员控制器和数据库管理功能
- 完善管理员操作日志系统
- 添加全面的属性测试覆盖
- 优化用户管理和用户档案服务
- 更新代码检查规范文档

功能改进:
- 增强管理员权限验证
- 完善操作日志记录
- 优化数据库管理接口
- 提升系统安全性和可维护性
2026-01-09 17:05:08 +08:00

436 lines
15 KiB
TypeScript

/**
* 用户管理模块集成测试
*
* 功能描述:
* - 测试用户管理模块的完整业务流程
* - 测试控制器与服务的集成
* - 测试真实的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/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<AdminService>;
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>(UserStatusController);
userManagementService = moduleFixture.get<UserManagementService>(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
});
});
});