【问题标题】:How to mock Jest Redis in Nestjs如何在 Nestjs 中模拟 Jest Redis
【发布时间】:2022-02-16 00:29:40
【问题描述】:

我正在开发 NestJs 应用程序,并在 user.service.ts 中为我的 authenticateUser 函数编写了单元测试。它已经传入我的本地机器。但是当我将它部署到服务器并运行单元测试时,出现错误Redis connection to 127.0.0.1:6379 failed - connect ECONNREFUSED.redis mock 好像不起作用。我应该如何模拟 redis 并解决这个问题才能正常工作?

user.service.ts

async authenticateUser(authDto: AuthDTO): Promise<AuthResponse> {
    try {
     const userData = await this.userRepository.findOne({msisdn});
     if(userData){
         await this.redisCacheService.setCache(msisdn, userData);
     }
    } catch (error) {
        console.log(error)
    }
}

redisCache.service.ts

export class RedisCacheService {
  constructor(
    @Inject(CACHE_MANAGER) private readonly cache: Cache,
  ) {}

  async setCache(key, value) {
    await this.cache.set(key, value);
  }
}

user.service.spec.ts

describe('Test User Service', () => {
  let userRepository: Repository<UserEntity>;
  let userService: UserService;
  let redisCacheService: RedisCacheService;
  let cacheManager: any;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        UserService,
        UserEntity,
        RedisCacheService,
        {
          provide: getRepositoryToken(UserEntity),
          useClass: registeredApplicationRepositoryMockFactory,
        },
      ],
      imports: [CacheModule.register({})],
    }).compile();

    userService = module.get<UserService>(UserService);
    userRepository = module.get<Repository<UserEntity>>(
      getRepositoryToken(UserEntity),
    );
    redisCacheService = module.get<RedisCacheService>(RedisCacheService);
    cacheManager = module.get<any>(CACHE_MANAGER);
  });

  it('authenticateUser should return success response', async () => {
    const userEntity = { id: 1, name: 'abc', age: 25 };
    const mockSuccessResponse = new AuthResponse(
      HttpStatus.OK,
      STRING.SUCCESS,
      `${STRING.USER} ${STRING.AUTHENTICATE} ${STRING.SUCCESS}`,
      {},
    );

    jest.spyOn(userRepository, 'findOne').mockResolvedValueOnce(userEntity);
    jest.spyOn(redisCacheService, 'setCache').mockResolvedValueOnce(null);

    expect(await userService.authenticateUser(mockAuthBody)).toEqual(mockSuccessResponse);
  });
});

【问题讨论】:

  • 看起来您的 RedisCacheService 正在加载随后尝试​​连接到 Redis 的 @Inject(CACHE_MANAGER)。您可以完全模拟 RedisCacheService 参见 jestjs.io/docs/es6-class-mocksjestjs.io/docs/manual-mocks
  • 是因为CACHE_MANAGER吗?我可以在这里模拟整个 redis 吗?
  • 您可以使用npm redis-server 并在创建TestingModule 之前创建一个Redis 实例(在BeforEach 中)。这样,将为每个测试创建一个临时 Redis-Server(只需添加 AfterEach 即可将其删除)。但是...如果您要编写单元测试,您应该模拟 RedisCacheService 而不是添加网络组件。

标签: node.js unit-testing redis jestjs nestjs


【解决方案1】:

您可以使用自定义提供程序模拟 CACHE_MANAGER:

import { CACHE_MANAGER } from '@nestjs/common';
import { Cache } from 'cache-manager';

describe('AppService', () => {
  let service: AppService;
  let cache: Cache;

  beforeEach(async () => {
    const app = await Test.createTestingModule({
      providers: [
        AppService,
        {
          provide: CACHE_MANAGER,
          useValue: {
            get: () => 'any value',
            set: () => jest.fn(),
          },
        },
      ],
    })
    .compile();

    service = app.get<AppService>(AppService);
    cache = app.get(CACHE_MANAGER);
  });

  // Then you can use jest.spyOn() to spy and mock

  it(`should cache the value`, async () => {
    const spy = jest.spyOn(cache, 'set');

    await service.cacheSomething();

    expect(spy).toHaveBeenCalledTimes(1);
    expect(spy.mock.calls[0][0]).toEqual('key');
    expect(spy.mock.calls[0][1]).toEqual('value');
  });

  it(`should get the value from cache`, async () => {
    const spy = jest.spyOn(cache, 'get');

    await service.getSomething();

    expect(spy).toHaveBeenCalledTimes(1);
  });

  it(`should return the value from the cache`, async () => {
    jest.spyOn(cache, 'get').mockResolvedValueOnce('value');
    
    const res = await service.getSomething();

    expect(res).toEqual('value');
  }),
});

有关自定义提供程序的更多详细信息:https://docs.nestjs.com/fundamentals/custom-providers

还有两件事,对于单元测试,您不应该导入模块,而是模拟依赖项。正如丹尼尔所说,UserService 使用的不是 CACHE_MANAGER 而是 RedisCacheService,所以你应该模拟 RedisCacheService。

通常最好的办法是只提供您正在测试的服务并模拟依赖项。

【讨论】:

  • 是的,这是模拟几乎所有测试的好方法
猜你喜欢
  • 2022-08-24
  • 1970-01-01
  • 2020-12-17
  • 2020-08-28
  • 1970-01-01
  • 2021-06-14
  • 1970-01-01
  • 1970-01-01
  • 2021-04-01
相关资源
最近更新 更多