【问题标题】:Mocking auto generated model functions created using sequelize-auto package模拟使用 sequelize-auto 包创建的自动生成的模型函数
【发布时间】:2021-11-26 21:55:49
【问题描述】:

我已经使用 sequelize-auto 包创建了我的模型并在我的控制器中使用了它们

const sequelize = require('../database/db');
var models = require("../models/init-models").initModels(sequelize);

var User = models.User;

const controllerMethod = async (req,res,next) => {
    //calls User.findAll() and returns the results
}

我在我的控制器方法之一中调用了 User 模型的 findAll 函数

我想使用 Jest 测试我的控制器方法,并想模拟 findAll 函数以返回一个空对象。 我已经在测试文件中导入了我的模型并模拟了 findAll 函数,如下所示,

//inside test case
            models.User.findAll = jest.fn().mockImplementation(() => {
                return {}
            });
            const spy = jest.spyOn(models.User, "findAll")
            await controllerMethod(req, res,next);

我的问题是,当我运行测试用例时,它会在控制器内部运行实际的 findAll() 函数,而不是模拟的 findAll()
即 findAll() 返回实际数据而不是 {}

任何帮助将不胜感激
提前致谢

【问题讨论】:

    标签: node.js jestjs sequelize.js sequelize-auto


    【解决方案1】:

    欢迎来到 Stack Overflow。我认为您的代码的问题是对spyOn 的工作方式有些混淆。请参阅文档here,具体如下:

    Note: By default, jest.spyOn also calls the spied method. This is different behavior from most other test libraries. If you want to overwrite the original function, you can use jest.spyOn(object, methodName).mockImplementation(() => customImplementation) or object[methodName] = jest.fn(() => customImplementation);
    

    这告诉您spyOn 实际调用的是原始方法,而不是模拟实现。

    我这样做的方式(假设您不需要断言如何调用findAll)根本不使用spyOn,而是创建一个从initModels返回的虚拟models,它上面有你的虚拟findAll 方法。类似于以下内容:

    const mockModels = {
            User: {
                findAll: jest.fn(() => {})
            }
        };
        // And then in your test - be careful as jest.mock is "hoisted" so you need to make sure mockModels has already been declared and assigned
    
    test('blah', () => {
        jest.mock("../models/init-models", () => ({
            initModels: jest.fn(() => mockModels,
        });
        await controllerMethod(req, res, next) // ...etc
    

    【讨论】:

    • 感谢您的回答。我在jest.mock 之后导入了我的模型,当我在测试用例中console.log(await models.User.findAll()) 时,它会打印{},但controllerMethod 仍然调用实际的findAll
    • 好的,controllerMethod 是如何实际调用该函数的?
    • 在 try 块中我有 const user = await User.findAll({where: {id: something}}) 。我稍后检查user.length != 0 是否返回我的结果,所以我想模拟findAll 使其返回一个空数组(不是对象哎呀)
    【解决方案2】:

    设法解决了我的问题,直到找到更好的解决方案。

    我创建了一个单独的 models.js 文件并通过它导出了我的所有模型。从models.js 文件而不是 const sequelize = require('../database/db'); var models = require("../models/init-models").initModels(sequelize); 将模型导入我的控制器

    models.js

    const sequelize = require('../database/db');
    var models = require("./init-models").initModels(sequelize);
    
    module.exports.User= models.User;
    module.exports.Instrument = models.Instrument;
    
    module.exports.sequelize = sequelize;  //exported this too since I have used sequelize.fn in some of my controllers
    

    userController.js

    //const sequelize = require('../database/db');
    //var models = require("../models/init-models").initModels(sequelize);
    
    //var User = models.User;
    const {User,sequelize} = require('../service/models');  //imported models this way
    
    const controllerMethod = async (req,res,next) => {
        //calls await User.findAll() and returns the results
    }
    

    userController.test.js

    const {controllerMethod} = require('../../../controllers/user');
    const {User,sequelize} = require('../../../service/models');
    
    //inside test case
               jest.spyOn(User, "findAll").mockImplementation(() => {return Promise.resolve([])});
               await controllerMethod(req, res,next);
    

    以这种方式findAll 模拟我想要的方式并返回预期的[]

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-05
      • 2021-10-03
      • 2015-03-06
      • 2019-08-18
      • 2021-03-17
      • 1970-01-01
      • 2014-01-05
      • 1970-01-01
      相关资源
      最近更新 更多