/** * 聊天业务模块测试 * * 测试范围: * - 模块配置验证 * - 服务提供者注册 * - 接口导出验证 * * @author moyin * @version 1.0.1 * @since 2026-01-14 * @lastModified 2026-01-19 * * 修改记录: * - 2026-01-19 moyin: Bug修复 - 添加缺失的ZulipAccountsService Mock配置 */ 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(), getUserClient: 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(), }; const mockZulipAccountsService = { findByGameUserId: 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, }, { provide: 'ZulipAccountsService', useValue: mockZulipAccountsService, }, ], }).compile(); chatService = module.get(ChatService); sessionService = module.get(ChatSessionService); filterService = module.get(ChatFilterService); cleanupService = module.get(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(); }); }); });