范围:src/business/chat/ - 实现 ChatService 聊天业务服务(登录/登出/消息发送/位置更新) - 实现 ChatSessionService 会话管理服务(会话创建/销毁/上下文注入) - 实现 ChatFilterService 消息过滤服务(频率限制/敏感词/权限验证) - 实现 ChatCleanupService 会话清理服务(定时清理过期会话) - 添加完整的单元测试覆盖 - 添加模块 README 文档
217 lines
6.6 KiB
TypeScript
217 lines
6.6 KiB
TypeScript
/**
|
|
* 聊天业务模块测试
|
|
*
|
|
* 测试范围:
|
|
* - 模块配置验证
|
|
* - 服务提供者注册
|
|
* - 接口导出验证
|
|
*
|
|
* @author moyin
|
|
* @version 1.0.0
|
|
* @since 2026-01-14
|
|
* @lastModified 2026-01-14
|
|
*/
|
|
|
|
import { Test, TestingModule } from '@nestjs/testing';
|
|
import { Logger } from '@nestjs/common';
|
|
import { ChatService } from './chat.service';
|
|
import { ChatSessionService } from './services/chat_session.service';
|
|
import { ChatFilterService } from './services/chat_filter.service';
|
|
import { ChatCleanupService } from './services/chat_cleanup.service';
|
|
import { SESSION_QUERY_SERVICE } from '../../core/session_core/session_core.interfaces';
|
|
import { LoginCoreService } from '../../core/login_core/login_core.service';
|
|
|
|
describe('ChatModule', () => {
|
|
let module: TestingModule;
|
|
let chatService: ChatService;
|
|
let sessionService: ChatSessionService;
|
|
let filterService: ChatFilterService;
|
|
let cleanupService: ChatCleanupService;
|
|
|
|
// Mock依赖
|
|
const mockZulipClientPool = {
|
|
createUserClient: jest.fn(),
|
|
destroyUserClient: jest.fn(),
|
|
sendMessage: jest.fn(),
|
|
};
|
|
|
|
const mockZulipConfigService = {
|
|
getStreamByMap: jest.fn().mockReturnValue('Test Stream'),
|
|
findNearbyObject: jest.fn().mockReturnValue(null),
|
|
getAllMapIds: jest.fn().mockReturnValue(['novice_village', 'whale_port']),
|
|
};
|
|
|
|
const mockApiKeySecurityService = {
|
|
getApiKey: jest.fn(),
|
|
deleteApiKey: jest.fn(),
|
|
};
|
|
|
|
const mockRedisService = {
|
|
get: jest.fn(),
|
|
setex: jest.fn(),
|
|
del: jest.fn(),
|
|
sadd: jest.fn(),
|
|
srem: jest.fn(),
|
|
smembers: jest.fn(),
|
|
expire: jest.fn(),
|
|
incr: jest.fn(),
|
|
};
|
|
|
|
const mockLoginCoreService = {
|
|
verifyToken: jest.fn(),
|
|
};
|
|
|
|
beforeEach(async () => {
|
|
// 禁用日志输出
|
|
jest.spyOn(Logger.prototype, 'log').mockImplementation();
|
|
jest.spyOn(Logger.prototype, 'error').mockImplementation();
|
|
jest.spyOn(Logger.prototype, 'warn').mockImplementation();
|
|
|
|
module = await Test.createTestingModule({
|
|
providers: [
|
|
ChatService,
|
|
ChatSessionService,
|
|
ChatFilterService,
|
|
ChatCleanupService,
|
|
{
|
|
provide: SESSION_QUERY_SERVICE,
|
|
useExisting: ChatSessionService,
|
|
},
|
|
{
|
|
provide: 'ZULIP_CLIENT_POOL_SERVICE',
|
|
useValue: mockZulipClientPool,
|
|
},
|
|
{
|
|
provide: 'ZULIP_CONFIG_SERVICE',
|
|
useValue: mockZulipConfigService,
|
|
},
|
|
{
|
|
provide: 'API_KEY_SECURITY_SERVICE',
|
|
useValue: mockApiKeySecurityService,
|
|
},
|
|
{
|
|
provide: 'REDIS_SERVICE',
|
|
useValue: mockRedisService,
|
|
},
|
|
{
|
|
provide: LoginCoreService,
|
|
useValue: mockLoginCoreService,
|
|
},
|
|
],
|
|
}).compile();
|
|
|
|
chatService = module.get<ChatService>(ChatService);
|
|
sessionService = module.get<ChatSessionService>(ChatSessionService);
|
|
filterService = module.get<ChatFilterService>(ChatFilterService);
|
|
cleanupService = module.get<ChatCleanupService>(ChatCleanupService);
|
|
});
|
|
|
|
afterEach(async () => {
|
|
if (module) {
|
|
await module.close();
|
|
}
|
|
jest.clearAllMocks();
|
|
});
|
|
|
|
describe('模块配置', () => {
|
|
it('应该成功编译模块', () => {
|
|
expect(module).toBeDefined();
|
|
});
|
|
|
|
it('应该提供 ChatService', () => {
|
|
expect(chatService).toBeDefined();
|
|
expect(chatService).toBeInstanceOf(ChatService);
|
|
});
|
|
|
|
it('应该提供 ChatSessionService', () => {
|
|
expect(sessionService).toBeDefined();
|
|
expect(sessionService).toBeInstanceOf(ChatSessionService);
|
|
});
|
|
|
|
it('应该提供 ChatFilterService', () => {
|
|
expect(filterService).toBeDefined();
|
|
expect(filterService).toBeInstanceOf(ChatFilterService);
|
|
});
|
|
|
|
it('应该提供 ChatCleanupService', () => {
|
|
expect(cleanupService).toBeDefined();
|
|
expect(cleanupService).toBeInstanceOf(ChatCleanupService);
|
|
});
|
|
});
|
|
|
|
describe('接口导出', () => {
|
|
it('应该导出 SESSION_QUERY_SERVICE 接口', () => {
|
|
const queryService = module.get(SESSION_QUERY_SERVICE);
|
|
expect(queryService).toBeDefined();
|
|
});
|
|
|
|
it('SESSION_QUERY_SERVICE 应该指向 ChatSessionService', () => {
|
|
const queryService = module.get(SESSION_QUERY_SERVICE);
|
|
expect(queryService).toBe(sessionService);
|
|
});
|
|
|
|
it('SESSION_QUERY_SERVICE 应该实现 ISessionManagerService 接口', () => {
|
|
const queryService = module.get(SESSION_QUERY_SERVICE);
|
|
expect(typeof queryService.createSession).toBe('function');
|
|
expect(typeof queryService.getSession).toBe('function');
|
|
expect(typeof queryService.destroySession).toBe('function');
|
|
expect(typeof queryService.injectContext).toBe('function');
|
|
});
|
|
});
|
|
|
|
describe('服务依赖注入', () => {
|
|
it('ChatService 应该能够获取所有依赖', () => {
|
|
expect(chatService).toBeDefined();
|
|
// 验证私有依赖通过检查服务是否正常工作
|
|
expect(chatService['sessionService']).toBeDefined();
|
|
expect(chatService['filterService']).toBeDefined();
|
|
});
|
|
|
|
it('ChatSessionService 应该能够获取所有依赖', () => {
|
|
expect(sessionService).toBeDefined();
|
|
});
|
|
|
|
it('ChatFilterService 应该能够获取所有依赖', () => {
|
|
expect(filterService).toBeDefined();
|
|
});
|
|
|
|
it('ChatCleanupService 应该能够获取所有依赖', () => {
|
|
expect(cleanupService).toBeDefined();
|
|
expect(cleanupService['sessionService']).toBeDefined();
|
|
});
|
|
});
|
|
|
|
describe('服务协作', () => {
|
|
it('ChatService 应该能够调用 ChatSessionService', async () => {
|
|
mockRedisService.get.mockResolvedValue(null);
|
|
const session = await chatService.getSession('test_socket');
|
|
expect(session).toBeNull();
|
|
});
|
|
|
|
it('ChatCleanupService 应该能够调用 ChatSessionService', async () => {
|
|
mockRedisService.smembers.mockResolvedValue([]);
|
|
const result = await cleanupService.triggerCleanup();
|
|
expect(result.cleanedCount).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe('模块导出验证', () => {
|
|
it('所有导出的服务应该可用', () => {
|
|
// ChatModule 导出的服务
|
|
expect(chatService).toBeDefined();
|
|
expect(sessionService).toBeDefined();
|
|
expect(filterService).toBeDefined();
|
|
expect(cleanupService).toBeDefined();
|
|
});
|
|
|
|
it('SESSION_QUERY_SERVICE 应该可供其他模块使用', () => {
|
|
const queryService = module.get(SESSION_QUERY_SERVICE);
|
|
expect(queryService).toBeDefined();
|
|
// 验证接口方法存在
|
|
expect(queryService.createSession).toBeDefined();
|
|
expect(queryService.getSession).toBeDefined();
|
|
expect(queryService.destroySession).toBeDefined();
|
|
});
|
|
});
|
|
});
|