TypeScript类构造器注入Redis客户端遇类型错误,求Mock测试方案
TypeScript下强类型Redis使用方案(支持Mock单元测试)
问题根源
你遇到的类型不匹配错误,本质是直接依赖RedisClientType具体类型时,版本差异或导入方式导致的类型定义冲突。解决核心是依赖抽象而非具体实现,既解决类型问题,又能轻松Mock客户端做单元测试。
步骤1:抽象Redis操作接口
先定义Service实际需要的Redis操作接口,避免直接绑定Redis官方类型:
// redis.ts import { createClient, type RedisClientType } from 'redis'; import config from '../../config'; // 定义Service依赖的缓存操作接口(按需添加方法) export interface ICacheClient { get(key: string): Promise<string | null>; set(key: string, value: string, options?: { EX?: number }): Promise<'OK'>; del(key: string): Promise<number>; } // 初始化Redis客户端(处理异步连接) let redisClient: RedisClientType; async function initRedisClient() { if (!redisClient) { redisClient = createClient({ url: config.redis_url }); redisClient.on('error', err => console.error('Redis连接错误:', err)); await redisClient.connect(); } return redisClient; } // 导出适配接口的客户端实例(确保连接完成) export async function getCacheClient(): Promise<ICacheClient> { const client = await initRedisClient(); return { get: key => client.get(key), set: (key, value, options) => client.set(key, value, options), del: key => client.del(key), }; }
步骤2:Service依赖抽象接口
让Service依赖自定义的ICacheClient接口,而非Redis官方类型:
// MyService.ts import type { ICacheClient } from './redis'; export default class MyService { private cacheClient: ICacheClient; constructor(cacheClient: ICacheClient) { this.cacheClient = cacheClient; } // 示例业务方法 async getCachedValue(key: string): Promise<string | null> { return this.cacheClient.get(key); } async setCachedValue(key: string, value: string, ttl?: number): Promise<void> { await this.cacheClient.set(key, value, ttl ? { EX: ttl } : undefined); } }
步骤3:业务代码中使用
确保Redis连接完成后再初始化Service:
// 使用示例 import { getCacheClient } from './redis'; import MyService from './MyService'; async function bootstrap() { const cacheClient = await getCacheClient(); const myService = new MyService(cacheClient); // 调用业务方法 await myService.setCachedValue('user:1', '{"name":"John"}', 3600); const user = await myService.getCachedValue('user:1'); console.log(user); } bootstrap();
步骤4:单元测试Mock客户端
用Jest为例,直接MockICacheClient接口即可,无需依赖真实Redis:
// MyService.test.ts import MyService from './MyService'; // Mock缓存客户端 const mockCacheClient = { get: jest.fn().mockResolvedValue('{"name":"MockedJohn"}'), set: jest.fn().mockResolvedValue('OK'), del: jest.fn().mockResolvedValue(1), }; describe('MyService', () => { let service: MyService; beforeEach(() => { jest.clearAllMocks(); service = new MyService(mockCacheClient); }); test('getCachedValue应返回Mock值', async () => { const result = await service.getCachedValue('user:1'); expect(result).toBe('{"name":"MockedJohn"}'); expect(mockCacheClient.get).toHaveBeenCalledWith('user:1'); }); test('setCachedValue应正确调用set方法', async () => { await service.setCachedValue('user:2', '{"name":"Jane"}', 1800); expect(mockCacheClient.set).toHaveBeenCalledWith('user:2', '{"name":"Jane"}', { EX: 1800 }); }); });
内容的提问来源于stack exchange,提问作者Andrew Johns
相关产品推荐
相关产品推荐

