【问题标题】:How to test Models (Mongoose) in a service (NestJS) with jest如何用 jest 在服务 (NestJS) 中测试模型 (Mongoose)
【发布时间】:2020-07-16 19:06:24
【问题描述】:

我有一个用 NestJS 完成的后端。在我的服务中,我注入了两个 Mongoose 模型。我使用 Jest 来测试服务。 模型按原样声明并注入到模块中:

quizes.providers.ts
import { Connection } from 'mongoose';
import { QuizSchema } from './schemas/quiz.schema';

export const quizesProviders = [
  {
    provide: 'CLASS_MODEL',
    useFactory: (connection: Connection) => connection.model('Quiz', QuizSchema),
    inject: ['DATABASE_CONNECTION'],
  },
];

users.providers.ts
import { Connection } from 'mongoose';
import { UserSchema } from './schemas/user.schema';

export const usersProviders = [
  {
    provide: 'USER_MODEL',
    useFactory: (connection: Connection) => connection.model('User', UserSchema),
    inject: ['DATABASE_CONNECTION'],
  },
];

模块示例:

quizes.module.ts
import { Module } from '@nestjs/common';
import { QuizesController } from './quizes.controller';
import { QuizesService } from './quizes.service';

import { quizesProviders } from './quizes.providers';

import { usersProviders } from '../auth/users.providers';

import { DatabaseModule } from 'src/database.module';
import { AuthModule } from 'src/auth/auth.module';

@Module({
  imports: [DatabaseModule, AuthModule],
  controllers: [QuizesController],
  providers: [QuizesService,
  ...quizesProviders, ...usersProviders]
})
export class QuizesModule {}

然后在我的服务中,我注入模型:

quizes.service.ts
@Injectable()
export class QuizesService {
    constructor(
        @Inject('CLASS_MODEL')
        private classModel: Model<Quiz>,
        @Inject('USER_MODEL')
        private userModel: Model<User>
      ) {}

在我的 quizes.spec.ts(开玩笑)中,我开始做类似的事情。它编译但不起作用:

import { Test } from '@nestjs/testing';
import * as mongoose from 'mongoose';
import { User } from 'src/auth/user.interface';
import { Quiz } from './quiz.interface';
import { databaseProviders } from '../database.providers';

const USER_MODEL:mongoose.Model<User> =  mongoose.model('User', UserSchema);

const CLASS_MODEL:mongoose.Model<Quiz> =  mongoose.model('Quiz', QuizSchema);

const mockingQuizModel = () => {
  find: jest.fn()
}

const mockingUserModel = () => {
 find: jest.fn()
}

const mockUser = {
  username: 'Test user'
}

describe('QuizesService', () => {
    let quizesService;
    let userModel , classModel;


    beforeEach(async () => {
        const module = await Test.createTestingModule({

            providers: [QuizesService, ...usersProviders, ...quizesProviders,...databaseProviders,
            {provide: USER_MODEL, useFactory: mockingUserModel},
            {provide: CLASS_MODEL, useFactory: mockingQuizModel},
        ],
        }).compile();

        quizesService = await module.get<QuizesService>(QuizesService);
        classModel = await module.get<mongoose.Model<Quiz>>(CLASS_MODEL)
        userModel = await module.get<mongoose.Model<User>>(USER_MODEL)

    })

    describe('getAllQuizes', ()=> {

        it('get all quizes', () => {
           expect(userModel.find).not.toHaveBeenCalled();
        })

    })
})

userModel 未定义,测试未退出。

【问题讨论】:

    标签: node.js mongoose jestjs nestjs


    【解决方案1】:

    固定

    你不应该对 module.get 使用 await

    quizesService = module.get<QuizesService>(QuizesService);
    clientClassModel = module.get(getModelToken('CLASS_MODEL'))
    clientUserModel =  module.get(getModelToken('USER_MODEL'))
    

    【讨论】:

      【解决方案2】:

      测试套件的设置是好的,但不是测试 我测试服务 getAllQuizes 方法

      这里是服务

      @Injectable()
      export class QuizesService {
          constructor(
              @InjectModel('CLASS_MODEL')
              private classModel: Model<Quiz>,
              @InjectModel('USER_MODEL')
              private userModel: Model<User>
            ) {}
      
      async getAllQuizes(user: User) : Promise<Quiz[]> {
        // console.log(user);
          let userId;
          try {
          const userEntity = await this.userModel.find({username: user.username}).exec();
          userId = userEntity[0]._id;
          } catch (error) {
            throw new NotFoundException('user not found');
      
          }
          return await this.classModel.find({user: userId}).exec();
      
      }
      

      这是测试

      it('get all quizes', async () => {
                  clientUserModel.find.mockResolvedValue('user1');
      
                  clientClassModel.find.mockResolvedValue([{title: 'test', description: 'test'}])
      
                 expect(clientUserModel.find).not.toHaveBeenCalled();
                 expect(clientClassModel.find).not.toHaveBeenCalled();
                 const result = quizesService.getAllQuizes(mockUser);
                 expect(clientUserModel.find).toHaveBeenCalled();
                 expect(clientClassModel.find).toHaveBeenCalled();
                 expect(result).toEqual([{title: 'test', description: 'test'}]);
      
              })
      

      我的测试是假的,因为断言 expect(clientClassModel.find).toHaveBeenCalled() 是假的 而在我的服务中,我第一次调用用户模型的 find 方法,第二次调用类模型的 find 方法

      【讨论】:

      • 我让它通过测试 NotFoundException
      【解决方案3】:

      终于测试通过了

      describe("getAllQuizes", () => {
        it("get all quizes, user not found", async () => {
          clientUserModel.find.mockRejectedValue("user not found");
          clientClassModel.find.mockResolvedValue([
            { title: "test", description: "test" },
          ]);
      
          expect(clientUserModel.find).not.toHaveBeenCalled();
          expect(clientClassModel.find).not.toHaveBeenCalled();
          const result = quizesService.getAllQuizes(mockUser).catch((err) => {
            expect(err.message).toEqual("user not found");
          });
          expect(clientUserModel.find).toHaveBeenCalled();
        });
      
        it("get all quizes, find quizzes", async () => {
          clientUserModel.find.mockReturnValue({
            _id: "1234",
            username: "Test user",
          });
          clientClassModel.find.mockResolvedValue([
            { title: "test", description: "test" },
          ]);
      
          expect(clientUserModel.find).not.toHaveBeenCalled();
          expect(clientClassModel.find).not.toHaveBeenCalled();
          const result = quizesService.getAllQuizes(mockUser).then((state) => {
            expect(clientUserModel.find).toHaveBeenCalled();
            expect(clientClassModel.find).toHaveBeenCalled();
            expect(state).toEqual([{ title: "test", description: "test" }]);
          });
      
          //
        });
      });
      

      【讨论】:

        【解决方案4】:

        使用NestJS官方定义的getModelToken函数:https://docs.nestjs.com/v6/ 技术 -> Mongo(向下滚动到测试部分)

        那么你的代码应该看起来像这样:

        import { getModelToken } from '@nestjs/mongoose';
        
        const mockRepository = {
            find() {
              return {};
            }
          };
        
        const module = await Test.createTestingModule({    
            providers: [ ...,
            {provide: getModelToken('CLASS_MODEL'), useValue: mockRepository,},
            {provide: getModelToken('USER_MODEL'), useValue: mockRepository,},
        ],
        ...
        

        【讨论】:

          猜你喜欢
          • 2019-08-29
          • 2020-11-20
          • 2018-08-07
          • 2019-11-22
          • 2017-02-24
          • 2019-12-28
          • 2022-01-06
          • 2019-12-22
          • 2020-03-22
          相关资源
          最近更新 更多