3
votes

I want to write a unit test for my nestjs 'Course' repository service (a service that has dependencies on Mongoose Model and Redis).

courses.repository.ts:

    import { Injectable, HttpException, NotFoundException } from "@nestjs/common";
    import { InjectModel } from "@nestjs/mongoose"
    import { Course } from "../../../../shared/course";
    import { Model } from "mongoose";
    import { RedisService } from 'nestjs-redis';


    @Injectable({}) 
    export class CoursesRepository {

      private redisClient;
      constructor(
        @InjectModel('Course') private courseModel: Model<Course>,
        private readonly redisService: RedisService,
      ) {
        this.redisClient = this.redisService.getClient();

      }


      async findAll(): Promise<Course[]> {
        const courses = await this.redisClient.get('allCourses');
        if (!courses) {
          console.log('return from DB');
          const mongoCourses = await this.courseModel.find();
          await this.redisClient.set('allCourses', JSON.stringify(mongoCourses), 'EX', 20);
          return mongoCourses;
        }

        console.log('return from cache');
        return JSON.parse(courses);
      }
}

The test is initialized this way:

beforeEach(async () => {
  const moduleRef = await Test.createTestingModule({
    imports: [
      MongooseModule.forRoot(MONGO_CONNECTION,  { 
        useNewUrlParser: true,
        useUnifiedTopology: true
      }),
      MongooseModule.forFeature([
        { name: "Course", schema: CoursesSchema },
        { name: "Lesson", schema: LessonsSchema }
      ]),
      RedisModule.register({})
    ],
      controllers: [CoursesController, LessonsController],
      providers: [
         CoursesRepository,
         LessonsRepository
        ],
    }).compile();

  coursesRepository = moduleRef.get<CoursesRepository>(CoursesRepository);
  redisClient = moduleRef.get<RedisModule>(RedisModule);

});

My Course repository service has 2 dependencies - Redis and Mongoose Model (Course). I would like to mock both of them.

If I was mocking a provider I would use that syntax:

providers: [
    {provide: CoursesRepository, useFactory: mockCoursesRepository},
     LessonsRepository
    ],

Can I create a mock Redis service which will be used instead of the an actual Redis service during a test?

How ?

Thanks, Yaron

1
Can you show the code of your CoursesRepository?Kim Kern

1 Answers

4
votes

You can mock your RedisService just as any other dependency. Since you are really interested in the Redis client and not the service, you have to create an intermediate mock for the service. For mongoose, you need the getModelToken method for getting the correct injection token, see this answer:

const redisClientMockFactory = // ...
const redisServiceMock = {getClient: () => redisClientMockFactory()}

providers: [
  { provide: RedisService, useValue: redisServiceMock },
  { provide: getModelToken('Course'), useFactory: courseModelMockFactory },
  CoursesRepository
],

Please also note, that you probably should not import modules in unit tests (unless it is a testing module). See this answer on a distinction between unit and e2e tests.

How to create mocks?

See this answer.