如果通过正在测试的类调用Jest模拟类依赖项,则返回未定义的结果



我正在尝试使用Jest为我的基本CRUD应用程序编写一些单元测试。我想测试的类是我的DB实体的存储库;项目",并且它依赖于我注入到其构造函数中的项目模型

目前,我能够成功地模拟项目模型及其组件,当我控制台记录对模拟函数的调用时,我得到了预期的结果。然而,一旦我用模拟的项目模型实例化了我的存储库(测试主题(;我试图在上面调用一个函数,该函数利用了前面提到的模拟函数,并得到了结果"strong>";未定义的"。

总结一下我的问题,当直接调用mock的一个函数时,它的行为与通过测试类间接调用mock函数时不同。这让我几天来一直在想我做错了什么。如有任何帮助,我们将不胜感激!这是我可以复制该问题的最低代码。

测试/存储库/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);
});

存储库/项目.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);
}

存储库/存储库.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)));
}
}

型号/接口/项目.ts

import mongoose from "mongoose";
interface IProjectSchema{
name: String,
description: String,
repo: String
}
export default interface IProjectDocument extends IProjectSchema, mongoose.Document {}

型号/项目.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);
}
}

型号/接口/文档.ts

import ISchema from "./schema";
import mongoose from "mongoose";

export default interface IDocument<T> extends mongoose.Document<any>{} 

我通过直接在测试主题上设置jest函数而不是通过项目模型来设置它,解决了这个问题。

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

const projectModelMock = mocked<ProjectModel>(container.resolve(ProjectModel), true);
//Below line was the problem!
// projectModelMock.model.findOne = jest.fn().mockResolvedValue(Fixtures.SingleObject1); <--- TURNS OUT THIS IS NOT NEEDED

it('hopefully works', async() => {
const testSubject = new ProjectRepository(projectModelMock); 
//This one did the trick
testSubject.model.findOne =  jest.fn().mockResolvedValue(Fixtures.SingleObject1);  // <--- HAD TO DO THIS INSTEAD
await expect(testSubject.getOne()).resolves.toEqual(Fixtures.SingleObject1);
});

最新更新