使用sequelize-mock测试时遇TypeError: User.findAll不是函数问题求助
使用sequelize-mock测试Sequelize模型时遇到
User.findAll is not a function错误的解决方法 问题背景
我正在为基于PostgreSQL和Sequelize的简易REST API编写单元测试,相关代码及报错如下:
User模型代码
const sequelize = require('./../database/config') const Sequelize = require('sequelize') module.exports = sequelize.define( 'User', { user_id: { type: Sequelize.UUID, primaryKey: true, defaultValue: Sequelize.UUIDV4, allowNull: false }, login: { type: Sequelize.STRING, allowNull: false }, password: { type: Sequelize.STRING, allowNull: false }, age: { type: Sequelize.INTEGER, allowNull: false }, is_deleted: { type: Sequelize.BOOLEAN, defaultValue: false, allowNull: false } }, { timestamps: false, tableName: 'users' } )
数据访问层代码
const User = require('../models/user') exports.getUserById = (userId) => { return User.findOne({ where: { user_id: userId, is_deleted: false } }) } exports.getAllUsers = () => { return User.findAll({ where: { is_deleted: false } }) }
测试代码
let { getAllUsers, } = require('./Users') jest.mock('../models/user', () => () => { const SequelizeMock = require('sequelize-mock') const dbMock = new SequelizeMock() const UserMock = dbMock.define( 'User', { user_id: '2', login: 'steve', password: 'good', age: 34, isDeleted: false } ) return UserMock }) describe('User database', () => { it("getAllUsers should return users", async () => { const users = await getAllUsers() expect(users.length).toBeTruthy() }) })
报错信息
> nodejs-mentoring-2022@1.0.0 test > jest --config ./jest.config.js --forceExit --coverage FAIL data-access/User.test.js User database × getAllUsers should return users (2 ms) ● User database › getAllUsers should return users TypeError: User.findAll is not a function 8 | 9 | exports.getAllUsers = () => { > 10 | return User.findAll({ where: { is_deleted: false } }) | ^ 11 | } 12 | 13 | exports.addOneUser = async (userData) => { at findAll (data-access/Users.js:10:15) at Object.getAllUsers (data-access/User.test.js:27:25) ----------|---------|----------|---------|---------|--------------------- File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s ----------|---------|----------|---------|---------|--------------------- All files | 50 | 100 | 16.66 | 50 | Users.js | 50 | 100 | 16.66 | 50 | 4,14-18,22,26-27,34 ----------|---------|----------|---------|---------|--------------------- Test Suites: 1 failed, 1 total Tests: 1 failed, 1 total Snapshots: 0 total Time: 0.973 s, estimated 1 s Ran all test suites. Force exiting Jest: Have you considered using `--detectOpenHandles` to detect async operations that kept running after all tests finished?
解决方法
问题核心是Jest mock的返回值不符合原始模型的导出结构:
原始模型直接导出sequelize.define()的结果(一个具备findAll等方法的模型对象),但当前mock返回的是一个函数,导致数据访问层引入的User是这个函数,而非模型对象,自然没有findAll方法。
修改后的测试代码:
let { getAllUsers } = require('./Users') jest.mock('../models/user', () => { const SequelizeMock = require('sequelize-mock') const dbMock = new SequelizeMock() return dbMock.define('User', { user_id: '2', login: 'steve', password: 'good', age: 34, is_deleted: false // 注意字段名要和原始模型一致,原始是is_deleted而非isDeleted }) }) describe('User database', () => { it("getAllUsers should return users", async () => { // 手动设置mock返回值,让测试逻辑更可控 require('../models/user').$queueResult([ { user_id: '1', login: 'alice', password: 'test', age: 28, is_deleted: false }, { user_id: '2', login: 'steve', password: 'good', age: 34, is_deleted: false } ]) const users = await getAllUsers() expect(users.length).toBe(2) expect(users[0].login).toBe('alice') }) })
额外注意两个细节:
- mock的字段名必须和原始模型完全一致,原始模型用的是
is_deleted,不要写成驼峰式的isDeleted,否则查询条件会匹配不到mock数据 - 使用
$queueResult可以提前指定mock模型方法的返回值,让测试结果更可预期,避免依赖默认的mock数据
内容的提问来源于stack exchange,提问作者IamCoder
相关产品推荐
相关产品推荐

