docs(zulip): 完善Zulip业务模块功能文档
范围: src/business/zulip/README.md - 补充对外提供的接口章节(14个公共方法) - 添加使用的项目内部依赖说明(7个依赖) - 完善核心特性描述(5个特性) - 添加潜在风险评估(4个风险及缓解措施) - 优化文档结构和内容完整性
This commit is contained in:
338
src/gateway/zulip/zulip_accounts.controller.spec.ts
Normal file
338
src/gateway/zulip/zulip_accounts.controller.spec.ts
Normal file
@@ -0,0 +1,338 @@
|
||||
/**
|
||||
* 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<any>;
|
||||
|
||||
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>(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();
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user