【问题标题】:Jest mocked class dependency returns undefined if called through class being tested如果通过正在测试的类调用 Jest 模拟类依赖项返回未定义
【发布时间】: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


    【解决方案1】:

    我已经通过直接在测试对象上设置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);
    });
    

    【讨论】:

      猜你喜欢
      • 2018-01-21
      • 2018-03-20
      • 1970-01-01
      • 1970-01-01
      • 2020-10-17
      • 2017-04-16
      • 2021-12-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多