如何用 jest 在服务 (NestJS) 中测试模型 (Mongoose)
Posted
技术标签:
【中文标题】如何用 jest 在服务 (NestJS) 中测试模型 (Mongoose)【英文标题】:How to test Models (Mongoose) in a service (NestJS) with jest 【发布时间】: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
未定义,测试未退出。
【问题讨论】:
【参考方案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,,
],
...
【讨论】:
以上是关于如何用 jest 在服务 (NestJS) 中测试模型 (Mongoose)的主要内容,如果未能解决你的问题,请参考以下文章