使用sequelize-auto生成模型后,Jest模拟findAll不生效如何解决?
Sequelize模型findAll方法Mock不生效解决方案
问题核心原因
你测试中模拟的models实例和控制器内部使用的models实例不是同一个对象:控制器每次引入init-models后都会调用initModels(sequelize)生成全新的models集合,你在测试文件中修改的是测试上下文单独初始化的models实例,自然不会影响控制器内部的逻辑。
另外你的测试写法还有两处问题:
- 先手动给
models.User.findAll赋值jest mock函数,又调用jest.spyOn属于重复操作,spyOn本身就会将目标方法包装为mock函数 findAll是异步方法,你直接返回普通对象而非Promise,即使mock生效也可能导致控制器中await相关逻辑异常
解决方案
方案1:将models封装为全局单例(推荐)
先统一models实例,避免重复初始化,后续所有业务代码和测试都共用同一个实例:
- 新建
models/index.js作为单例导出文件:
const sequelize = require('../database/db'); const { initModels } = require("./init-models"); // 全局只初始化一次models module.exports = initModels(sequelize);
- 修改控制器中的引入逻辑:
// 统一引入单例models,不要单独执行initModels const models = require("../models/index"); const User = models.User; const controllerMethod = async (req,res,next) => { // 原有逻辑不变 }
- 测试文件中直接对单例的findAll做模拟:
const models = require("../models/index"); // inside test case // mock异步方法直接用mockResolvedValue返回Promise const findAllSpy = jest.spyOn(models.User, "findAll").mockResolvedValue({}); await controllerMethod(req, res, next); // 可添加断言验证调用 expect(findAllSpy).toHaveBeenCalled();
方案2:直接mock initModels方法
如果不想修改原有业务代码,可以直接mockinit-models模块,让所有调用initModels的地方都返回你预设的mock对象:
在测试文件顶部添加mock逻辑:
// 全局mock init-models模块 jest.mock('../models/init-models', () => ({ initModels: jest.fn(() => ({ User: { findAll: jest.fn().mockResolvedValue({}) } })) }));
之后无论控制器还是测试文件调用initModels,返回的User实例上的findAll都是你模拟的方法。
内容的提问来源于stack exchange,提问作者cmgchess
相关产品推荐
相关产品推荐

