You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为NestJS中的IoRedis创建Mock服务并解决测试启动问题

解决NestJS中Redis Service测试依赖问题

问题根源

你的Redis Service在构造函数中直接硬编码实例化Redis.Cluster,导致测试时会尝试连接真实Redis集群,无法实现测试隔离;同时因为没有通过依赖注入提供客户端实例,ioredis-mock无法替换真实的集群客户端,所以mock无效。

解决方案步骤

1. 重构RedisService,引入依赖注入

将Redis集群客户端的创建逻辑抽离为可注入的Provider,让客户端实例可以被测试环境替换:

import * as Redis from 'ioredis';
import { Injectable, Logger, Inject } from '@nestjs/common';
import {
  REDIS_HA_URL,
  REDIS_HA_PASSWORD,
  REDIS_PORT,
} from '../config/config.service';

// 定义注入令牌,用于标识Redis集群客户端
export const REDIS_CLUSTER_CLIENT = 'REDIS_CLUSTER_CLIENT';

@Injectable()
export class RedisService {
  private logger = new Logger('Redis Service');

  // 通过依赖注入获取Redis集群客户端
  constructor(@Inject(REDIS_CLUSTER_CLIENT) public readonly client: Redis.Cluster) {
    this.client.on('error', (error: any) => {
      this.logger.error(`Redis error ${error}`);
    });
    this.client.on('reconnecting', () =>
      this.logger.error('Redis reconnecting...'),
    );
  }
}

// 定义创建Redis集群客户端的Provider
export const redisClusterProvider = {
  provide: REDIS_CLUSTER_CLIENT,
  useFactory: () => {
    const hosts = REDIS_HA_URL.map(element => ({ host: element, port: REDIS_PORT }));
    return new Redis.Cluster(hosts, {
      redisOptions: {
        reconnectOnError() {
          return 2;
        },
        password: REDIS_HA_PASSWORD,
      },
    });
  },
};

2. 在测试中替换为ioredis-mock客户端

首先安装依赖:

npm install ioredis-mock --save-dev

然后编写测试用例,通过NestJS的测试模块替换真实客户端为mock实例:

import { Test, TestingModule } from '@nestjs/testing';
import { RedisService, REDIS_CLUSTER_CLIENT } from './redis.service';
import * as RedisMock from 'ioredis-mock';

// Mock配置文件,避免测试读取真实环境变量
jest.mock('../config/config.service', () => ({
  REDIS_HA_URL: ['localhost'],
  REDIS_HA_PASSWORD: 'mock-password',
  REDIS_PORT: 6379,
}));

describe('RedisService', () => {
  let service: RedisService;
  let mockCluster: RedisMock.Cluster;

  beforeEach(async () => {
    // 创建mock的Redis集群客户端
    mockCluster = new RedisMock.Cluster([{ host: 'localhost', port: 6379 }], {
      redisOptions: { password: 'mock-password' },
    });

    const module: TestingModule = await Test.createTestingModule({
      providers: [
        RedisService,
        {
          provide: REDIS_CLUSTER_CLIENT,
          useValue: mockCluster, // 用mock客户端替换真实实例
        },
      ],
    }).compile();

    service = module.get<RedisService>(RedisService);
  });

  it('服务应被正确实例化', () => {
    expect(service).toBeDefined();
    expect(service.client).toBe(mockCluster);
  });

  // 可添加更多测试用例,比如验证错误监听逻辑
  it('错误事件应触发日志输出', () => {
    const errorLogSpy = jest.spyOn(service['logger'], 'error');
    const testError = new Error('Test Redis Error');
    
    mockCluster.emit('error', testError);
    
    expect(errorLogSpy).toHaveBeenCalledWith(`Redis error ${testError}`);
  });
});

3. 依赖RedisService的其他服务测试

对于依赖RedisService的业务服务,只需在测试模块中同样替换REDIS_CLUSTER_CLIENT为mock实例即可,测试将完全隔离,不会启动真实Redis连接或整个项目。

内容的提问来源于stack exchange,提问作者Shemm11

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 12:32:36