Jest结合sequelize-mock mock Sequelize时findAll不存在的问题咨询
报错核心原因
当前mock逻辑和业务代码的调用逻辑完全错位:
- 业务代码中服务层的调用规则是
models.user.findAll(),即models.user本身是承载模型所有静态方法(findAll、findByPk等)的对象,findAll是这个对象的直接属性 - 现有mock写法将
models.user定义为一个普通的jest模拟函数,又通过mockImplementation让这个函数被调用后才返回SequelizeMock实例。实际运行时models.user指向函数本体,函数上没有挂载findAll方法,因此直接抛出TypeError: models.user.findAll is not a function。
直接替换真实模型为SequelizeMock实例的正确实现
不需要给models.user套一层函数包装,直接在jest mock工厂中将models.user指向SequelizeMock生成的、和真实模型API完全一致的模拟实例即可,适配TDD落地测试的全场景需求:
// 测试文件顶部引入依赖 const request = require('supertest'); const SequelizeMock = require('sequelize-mock'); const app = require('..'); // 初始化SequelizeMock实例 const dbMock = new SequelizeMock(); // 定义和真实User模型结构一致的模拟模型 const UserMock = dbMock.define('user', {}); // 队列化预设findAll方法的返回值,匹配真实数据库查询的结果结构 UserMock.$queueResult([ UserMock.build({ username: 'username', mail: 'myMail@myMail.com', }) ]); // 替换真实models模块,直接将user属性绑定到SequelizeMock生成的完整模型对象 jest.mock('../src/database/models/index', () => ({ user: UserMock })); describe('全量用户查询接口测试', () => { it('GET /users 接口返回正常', (done) => { request(app) .get('/users') .end((err, res) => { expect(err).toBeNull(); expect(res.status).toBe(200); // 修正原有断言的错误:supertest的响应解析结果存在res.body中,直接断言返回内容 expect(res.body).toEqual([ { username: 'username', mail: 'myMail@myMail.com' } ]); done(); }); }); });
两种Mock方案的场景选择
SequelizeMock全量替换方案:适合以TDD为默认开发模式的项目,后续如果服务层增加排序、条件筛选、关联查询等数据库操作逻辑,不需要手动修改mock实现,和真实Sequelize模型的API一致性更高,能最大程度减少测试代码和生产逻辑的偏差。
手动单方法mock方案:即你提到的直接给findAll写模拟实现的写法,适合仅需要快速验证接口链路连通性的轻量测试场景,示例:
jest.mock('../src/database/models/index', () => ({ user: { findAll: jest.fn().mockResolvedValue([{ id: 1, username: 'test' }]) } }));
这种方式的维护成本较高,后续只要服务层的数据库调用逻辑发生变化,就需要手动同步修改mock的实现,不适合长期迭代的项目使用。
内容的提问来源于stack exchange,提问作者Julian Mendez
相关产品推荐
相关产品推荐

