【发布时间】:2023-03-27 10:15:01
【问题描述】:
我正在尝试使用 Jest 为我的基本 CRUD 应用程序编写一些单元测试。我要测试的类是我的数据库实体 "Project" 的 repository,它依赖于我注入的 project model进入它的构造函数。
目前,我能够成功地模拟项目模型及其组件,当我在控制台记录模拟函数的调用时,我得到了预期的结果。但是,一旦我使用模拟项目模型实例化我的存储库(测试对象);我尝试在其上调用一个使用上述模拟函数的函数并得到结果 "undefined" 。
总结一下我的问题,当直接调用其中一个函数而不是通过测试类间接调用模拟函数时,模拟的行为不同这几天让我想知道我做错了什么。任何帮助将不胜感激!这是我可以重现该问题的最少代码。
测试/存储库/project.spec.ts
import "reflect-metadata";
import { container } from "tsyringe";
import ProjectRepository from "../../src/repositories/project";
import ProjectModel from "../../src/models/project";
import Fixtures from "../fixtures";
import { mocked } from 'ts-jest/utils';
jest.mock('../../src/models/project', () => {
return jest.fn().mockImplementation(() => {
return {
model: jest.fn()
}
})
});
// using mocked() helper to have the types of the object being mocked types on the actual mock.
const projectModelMock = mocked<ProjectModel>(container.resolve(ProjectModel), true);
//setting resolved value to be fixture data for each function to be faked.
projectModelMock.model.findOne = jest.fn().mockResolvedValue(Fixtures.SingleObject1);
console.log(projectModelMock.model.findOne());
// Above line Prints:
// Promise {
// {
// _id: '60901d3237604b90b072ef01',
// description: 'net core',
// name: 'authorization server',
// repo: 'aliboy.com'
// }
// }
// Works as expected when used here, doesn't work as expected when called through subject under test.
it('hopefully works', () => {
//instantiating the class to be tested with the mocked dependency
const testSubject = new ProjectRepository(projectModelMock);
//calling a class method which makes a call to the findOne() function being mocked.
expect(testSubject.getOne()).resolves.toEqual(Fixtures.SingleObject1);
});
存储库/project.ts
import mongoose from "mongoose";
import mongodb from "mongodb";
import { autoInjectable, singleton } from "tsyringe";
import IProjectDocument from "../models/interfaces/project";
import IResponseModel from "../models/interfaces/response";
import ProjectModel from "../models/project";
import ResponseModel from "../models/response";
import BaseRepository from "./repository";
import IDocument from "../models/interfaces/document";
@singleton()
@autoInjectable()
export default class ProjectRepository extends BaseRepository<IDocument<IProjectDocument>>{
constructor(model: ProjectModel){
super(model.model);
}
repositories/repository.ts
import mongoose from "mongoose";
import IDocument from "../models/interfaces/document";
import ResponseModel from "../models/response";
export default class BaseRepository<T>{
model: mongoose.Model<any, any>
constructor(model: mongoose.Model<IDocument<T>>){
this.model = model;
}
getOne = async (filters = {}): Promise<ResponseModel<T>> => {
try{
console.log( this.model.findOne());
//Above line prints: **undefined**
//This is unexpected and should print Promise{object} instead.
const result : T = await this.model.findOne(filters); //<-- **Problematic Line**
if(result != null){
return Promise.resolve(new ResponseModel(true, result, `Single object fetched successfully`));
}
return Promise.resolve(new ResponseModel(false, result, `Single object not found`));
} catch(e){
return Promise.reject(new ResponseModel(false, void(0), String(e)));
}
}
模型/接口/project.ts
import mongoose from "mongoose";
interface IProjectSchema{
name: String,
description: String,
repo: String
}
export default interface IProjectDocument extends IProjectSchema, mongoose.Document {}
models/project.ts
import mongoose from "mongoose";
import { autoInjectable, injectable, singleton } from "tsyringe";
import IDocument from "./interfaces/document";
import IModel from "./interfaces/model";
import IProjectDocument from "./interfaces/project";
@singleton()
@autoInjectable()
export default class ProjectModel implements IModel {
schema: mongoose.Schema;
model : mongoose.Model<IDocument<IProjectDocument>>;
constructor() {
this.schema = new mongoose.Schema({
name: String,
description: String,
repo: String,
_id: mongoose.Schema.Types.ObjectId
})
this.model = mongoose.model<IDocument<IProjectDocument>>("projects", this.schema);
}
}
模型/接口/document.ts
import ISchema from "./schema";
import mongoose from "mongoose";
export default interface IDocument<T> extends mongoose.Document<any>{}
【问题讨论】:
标签: node.js typescript unit-testing jestjs ts-jest