如何让Jest等待/阻止Sequelize数据库连接以消除日志错误
Node Express + Sequelize 单元测试:解决"Cannot log after tests are done"问题
问题背景
为使用Sequelize(SQLite)的Node Express应用编写控制器单元测试时,因控制器导入User模型触发了Sequelize的数据库连接与sync操作,导致测试执行完毕后,Sequelize的异步日志仍在输出,出现大量"Cannot log after tests are done"错误。测试本身能通过,但日志污染问题严重,需要要么阻止Sequelize初始化(用Mock替代真实DB),要么让Jest等待所有异步进程完成。
方案1:Mock Sequelize与模型(推荐,彻底隔离真实数据库)
单元测试无需真实数据库连接,直接Mock模型方法即可,同时阻止Sequelize的真实初始化。
步骤1:Mock Sequelize核心模块
在测试文件顶部添加代码,阻止Sequelize实例化时建立真实连接:
// Mock数据库初始化模块,避免真实连接 jest.mock('../../database/db', () => ({ sqlzDB: { define: jest.fn().mockReturnValue({ create: jest.fn() }) } }));
步骤2:调整测试中的Mock逻辑
直接Mock控制器依赖的User模型,无需导入真实模型:
import { registerUser } from '../controllers/user'; describe('testing user registration', () => { let mRes: Response<any, Record<string, any>>; let mNext; const createdUser = { id: 1, email: 'test@example.com', role: 'user' }; beforeAll(()=>{ mRes = { status: jest.fn().mockReturnThis(), json: jest.fn() }; mNext = jest.fn(err => err); // Mock控制器中导入的User模型 jest.mock('../models/user', () => ({ create: jest.fn().mockResolvedValue(createdUser) })); }) afterAll(()=>{ jest.resetAllMocks(); }) test('with invalid email', async () => { const mReqInvalidEmail = { body: { email: 'invalid-email', role: 'user' } }; await registerUser(mReqInvalidEmail, mRes, mNext); expect(mNext).toBeCalledWith(expect.objectContaining({ statusCode: 400 })); }) })
步骤3:优化Sequelize初始化代码(可选)
为生产/测试环境自动切换,将初始化逻辑封装为条件执行:
const {Sequelize} = require('sequelize'); export const sqlzDB = new Sequelize({ dialect: 'sqlite', storage: 'database/db.sqlite' }); // 仅在非测试环境执行连接与同步 if (process.env.NODE_ENV !== 'test') { sqlzDB.authenticate() .then(()=>{ console.log('Connection to database established successfully.'); }).catch((err : Error)=> { console.log('Unable to connect to the database: ', err); }); sqlzDB.sync().then(()=>{ console.log('Sequelize Synced'); }); }
方案2:让Jest等待异步进程完成(适合需要真实DB的集成测试)
如果必须使用真实数据库,需让Jest等待Sequelize的连接和sync完成,测试结束后关闭连接。
步骤1:修改Sequelize初始化代码,导出异步操作Promise
const {Sequelize} = require('sequelize'); export const sqlzDB = new Sequelize({ dialect: 'sqlite', storage: 'database/db.sqlite' }); // 导出连接与同步的Promise集合 export const dbInit = Promise.all([ sqlzDB.authenticate(), sqlzDB.sync() ]); dbInit .then(()=>{ console.log('Database connected and synced successfully.'); }).catch((err : Error)=> { console.log('Database init failed: ', err); });
步骤2:在测试中等待DB初始化,结束后关闭连接
import { sqlzDB, dbInit } from '../../database/db'; import { registerUser } from '../controllers/user'; import UserModel from '../models/user'; describe('testing user registration', () => { let mRes: Response<any, Record<string, any>>; let mNext; const createdUser = { id: 1, email: 'test@example.com', role: 'user' }; beforeAll(async ()=>{ // 等待数据库初始化完成 await dbInit; mRes = { status: jest.fn().mockReturnThis(), json: jest.fn() }; mNext = jest.fn(err => err); jest.spyOn(UserModel, 'create').mockResolvedValue(createdUser); }) afterAll(async ()=>{ jest.resetAllMocks(); // 关闭数据库连接 await sqlzDB.close(); }) test('with invalid email', async () => { const mReqInvalidEmail = { body: { email: 'invalid-email', role: 'user' } }; await registerUser(mReqInvalidEmail, mRes, mNext); expect(mNext).toBeCalledWith(expect.objectContaining({ statusCode: 400 })); }) })
内容的提问来源于stack exchange,提问作者xunux
相关产品推荐
相关产品推荐

