You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 06:55:17