skip to Main Content

I’m working on NestJs application and wrote unit test for my authenticateUser function in user.service.ts.It’s has pass in my local machine.but when I deployed it in to server and run unit test, i got an error Redis connection to 127.0.0.1:6379 failed - connect ECONNREFUSED.Seems like redis mock is not working.How should I mock redis and resolve this issue for working?

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);
  });
});

enter image description here

3

Answers


  1. You can mock CACHE_MANAGER using a custom provider:

    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');
      }),
    });
    

    More details on Custom Providers: https://docs.nestjs.com/fundamentals/custom-providers

    Two more things, for unit testing you shouldn’t import modules but mock the dependencies instead. And as Daniel said, UserService is not using CACHE_MANAGER but RedisCacheService, so you should mock RedisCacheService.

    Usually the best thing to do is to only provide the service you’re testing and mock the dependencies.

    Login or Signup to reply.
  2. in order to use the jest spy functions you need to return the jest function directly.

        providers: [
            AppService,
            {
              provide: CACHE_MANAGER,
              useValue: {
                get: () => 'any value',
                set: jest.fn(),
              },
            },
          ],
    
    Login or Signup to reply.
  3. To solve this problem I overrode the CACHE_MANAGER

    beforeEach(async () => {
            const app = await Test.createTestingModule({
              providers: [
                AppService,
                {
                  provide: CACHE_MANAGER,
                  useValue: {
                    get: () => 'any value',
                    set: () => jest.fn(),
                  },
                },
              ],
            }).overrideProvider(CACHE_MANAGER)
              .useValue({
                  get: jest.fn(),
                  set: jest:fn()
             }).compile();
        
            service = app.get<AppService>(AppService);
            cache = app.get(CACHE_MANAGER);
          });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search