/** * Zulip账号管理控制器测试 * * 功能描述: * - 测试Zulip账号关联管理功能 * - 验证账号创建和验证逻辑 * - 测试账号状态管理和更新 * - 验证错误处理和异常情况 * * 测试范围: * - 账号关联API测试 * - 账号验证功能测试 * - 状态管理测试 * - 错误处理测试 * * 最近修改: * - 2026-01-12: 测试修复 - 修正测试方法名称和Mock配置,确保与实际控制器方法匹配 (修改者: moyin) * - 2026-01-12: 代码规范优化 - 创建测试文件,确保Zulip账号管理控制器功能的测试覆盖 (修改者: moyin) * * @author moyin * @version 1.1.0 * @since 2026-01-12 * @lastModified 2026-01-12 */ import { Test, TestingModule } from '@nestjs/testing'; import { HttpException, HttpStatus } from '@nestjs/common'; import { ZulipAccountsController } from './zulip_accounts.controller'; import { JwtAuthGuard } from '../auth/jwt_auth.guard'; import { AppLoggerService } from '../../core/utils/logger/logger.service'; import { ZulipAccountsBusinessService } from '../../business/zulip/services/zulip_accounts_business.service'; describe('ZulipAccountsController', () => { let controller: ZulipAccountsController; let zulipAccountsService: jest.Mocked; beforeEach(async () => { const mockZulipAccountsService = { create: jest.fn(), findMany: jest.fn(), findById: jest.fn(), findByGameUserId: jest.fn(), findByZulipUserId: jest.fn(), findByZulipEmail: jest.fn(), update: jest.fn(), updateByGameUserId: jest.fn(), delete: jest.fn(), deleteByGameUserId: jest.fn(), findAccountsNeedingVerification: jest.fn(), findErrorAccounts: jest.fn(), batchUpdateStatus: jest.fn(), getStatusStatistics: jest.fn(), verifyAccount: jest.fn(), existsByEmail: jest.fn(), existsByZulipUserId: jest.fn(), }; const module: TestingModule = await Test.createTestingModule({ controllers: [ZulipAccountsController], providers: [ { provide: 'ZulipAccountsService', useValue: mockZulipAccountsService }, { provide: AppLoggerService, useValue: { info: jest.fn(), error: jest.fn(), bindRequest: jest.fn().mockReturnValue({ info: jest.fn(), error: jest.fn(), }), }}, ], }) .overrideGuard(JwtAuthGuard) .useValue({ canActivate: () => true }) .compile(); controller = module.get(ZulipAccountsController); zulipAccountsService = module.get('ZulipAccountsService'); }); describe('Controller Initialization', () => { it('should be defined', () => { expect(controller).toBeDefined(); }); it('should have zulip accounts service dependency', () => { expect(zulipAccountsService).toBeDefined(); }); }); describe('create', () => { const validCreateDto = { gameUserId: 'game123', zulipUserId: 456, zulipEmail: 'user@example.com', zulipFullName: 'Test User', zulipApiKeyEncrypted: 'encrypted_api_key_123', status: 'active' as const, }; it('should create Zulip account successfully', async () => { // Arrange const expectedResult = { id: 'acc123', gameUserId: validCreateDto.gameUserId, zulipUserId: validCreateDto.zulipUserId, zulipEmail: validCreateDto.zulipEmail, zulipFullName: validCreateDto.zulipFullName, status: 'active', retryCount: 0, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), }; zulipAccountsService.create.mockResolvedValue(expectedResult); // Act const result = await controller.create({} as any, validCreateDto); // Assert expect(result).toEqual(expectedResult); expect(zulipAccountsService.create).toHaveBeenCalledWith(validCreateDto); }); it('should handle service errors during account creation', async () => { // Arrange zulipAccountsService.create.mockRejectedValue( new Error('Database error') ); // Act & Assert await expect(controller.create({} as any, validCreateDto)).rejects.toThrow(); }); }); describe('findByGameUserId', () => { const gameUserId = 'game123'; it('should return account information', async () => { // Arrange const expectedInfo = { id: 'acc123', gameUserId: gameUserId, zulipUserId: 456, zulipEmail: 'user@example.com', status: 'active', createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), }; zulipAccountsService.findByGameUserId.mockResolvedValue(expectedInfo); // Act const result = await controller.findByGameUserId(gameUserId, false); // Assert expect(result).toEqual(expectedInfo); expect(zulipAccountsService.findByGameUserId).toHaveBeenCalledWith(gameUserId, false); }); it('should handle account not found', async () => { // Arrange zulipAccountsService.findByGameUserId.mockResolvedValue(null); // Act const result = await controller.findByGameUserId(gameUserId, false); // Assert expect(result).toBeNull(); }); it('should handle service errors', async () => { // Arrange zulipAccountsService.findByGameUserId.mockRejectedValue( new Error('Database error') ); // Act & Assert await expect(controller.findByGameUserId(gameUserId, false)).rejects.toThrow(); }); }); describe('deleteByGameUserId', () => { const gameUserId = 'game123'; it('should delete account successfully', async () => { // Arrange zulipAccountsService.deleteByGameUserId.mockResolvedValue(undefined); // Act const result = await controller.deleteByGameUserId(gameUserId); // Assert expect(result).toEqual({ success: true, message: '删除成功' }); expect(zulipAccountsService.deleteByGameUserId).toHaveBeenCalledWith(gameUserId); }); it('should handle account not found during deletion', async () => { // Arrange zulipAccountsService.deleteByGameUserId.mockRejectedValue( new Error('Account not found') ); // Act & Assert await expect(controller.deleteByGameUserId(gameUserId)).rejects.toThrow(); }); }); describe('getStatusStatistics', () => { it('should return account statistics', async () => { // Arrange const expectedStats = { total: 100, active: 80, inactive: 15, suspended: 3, error: 2, }; zulipAccountsService.getStatusStatistics.mockResolvedValue(expectedStats); // Act const result = await controller.getStatusStatistics({} as any); // Assert expect(result).toEqual(expectedStats); expect(zulipAccountsService.getStatusStatistics).toHaveBeenCalled(); }); it('should handle service errors', async () => { // Arrange zulipAccountsService.getStatusStatistics.mockRejectedValue( new Error('Database error') ); // Act & Assert await expect(controller.getStatusStatistics({} as any)).rejects.toThrow(); }); }); describe('verifyAccount', () => { const verifyDto = { gameUserId: 'game123' }; it('should verify account successfully', async () => { // Arrange const validationResult = { isValid: true, gameUserId: verifyDto.gameUserId, zulipUserId: 456, status: 'active', lastValidated: new Date().toISOString(), }; zulipAccountsService.verifyAccount.mockResolvedValue(validationResult); // Act const result = await controller.verifyAccount(verifyDto); // Assert expect(result).toEqual(validationResult); expect(zulipAccountsService.verifyAccount).toHaveBeenCalledWith(verifyDto.gameUserId); }); it('should handle invalid account', async () => { // Arrange const validationResult = { isValid: false, gameUserId: verifyDto.gameUserId, error: 'Account suspended', lastValidated: new Date().toISOString(), }; zulipAccountsService.verifyAccount.mockResolvedValue(validationResult); // Act const result = await controller.verifyAccount(verifyDto); // Assert expect(result).toEqual(validationResult); expect(result.isValid).toBe(false); }); it('should handle validation errors', async () => { // Arrange zulipAccountsService.verifyAccount.mockRejectedValue( new Error('Validation service error') ); // Act & Assert await expect(controller.verifyAccount(verifyDto)).rejects.toThrow(); }); }); describe('checkEmailExists', () => { const email = 'user@example.com'; it('should check if email exists', async () => { // Arrange zulipAccountsService.existsByEmail.mockResolvedValue(false); // Act const result = await controller.checkEmailExists(email); // Assert expect(result).toEqual({ exists: false, email }); expect(zulipAccountsService.existsByEmail).toHaveBeenCalledWith(email, undefined); }); it('should handle service errors when checking email', async () => { // Arrange zulipAccountsService.existsByEmail.mockRejectedValue( new Error('Database error') ); // Act & Assert await expect(controller.checkEmailExists(email)).rejects.toThrow(); }); }); describe('Error Handling', () => { it('should handle service unavailable errors', async () => { // Arrange zulipAccountsService.findByGameUserId.mockRejectedValue( new Error('Service unavailable') ); // Act & Assert await expect(controller.findByGameUserId('game123', false)).rejects.toThrow(); }); it('should handle malformed request data', async () => { // Arrange const malformedDto = { invalid: 'data' }; // Act & Assert await expect(controller.create({} as any, malformedDto as any)).rejects.toThrow(); }); }); });