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

TypeScript项目中如何为Sequelize.authenticate配置两种Jest模拟?

解决Sequelize authenticate方法的多场景测试问题

你的问题核心在于jest.mock会被提升到模块顶部,导致测试内的mock逻辑无法覆盖之前的实例,且已导入的DB单例会使用真实的Sequelize构造函数,触发dialect校验错误。以下是两种可行的解决方案:

方案一:顶层Mock+动态修改mock行为

先在模块顶部统一Mock Sequelize,再在每个测试中动态调整authenticate的返回值,同时重置模块缓存确保每次测试使用新的实例。

步骤1:顶层Mock Sequelize

在测试文件最顶部添加:

import { Sequelize } from 'sequelize';

// 顶层Mock Sequelize构造函数,返回带mock authenticate方法的实例
jest.mock('sequelize', () => {
  const actualSequelize = jest.requireActual('sequelize');
  const mockSequelizeInstance = {
    authenticate: jest.fn() // 先定义为空mock函数,后续修改实现
  };
  return {
    Sequelize: jest.fn(() => mockSequelizeInstance),
    DataTypes: actualSequelize.DataTypes,
    Dialect: actualSequelize.Dialect // 保留真实的Dialect类型,避免类型错误
  };
});

步骤2:编写测试用例

使用jest.resetModules()重置模块缓存,确保每次测试重新导入DB实例和业务模块:

describe('健康检查测试', () => {
  beforeEach(() => {
    jest.resetModules(); // 重置模块缓存,避免单例实例复用
    jest.clearAllMocks(); // 清除mock调用记录
  });

  test('数据库连接正常时返回健康状态', async () => {
    // 修改authenticate为成功返回
    (Sequelize as jest.Mock).mock.results[0].value.authenticate.mockResolvedValue(undefined);

    // 动态导入所需模块(必须在mock修改后导入)
    const DBInstance = (await import('../path/to/DBInstance')).default;
    const HealthCheck = (await import('../path/to/HealthCheck')).default;

    const healthCheck = new HealthCheck(DBInstance);
    const result = await healthCheck.checkHealthStatus();
    expect(result).toEqual(true);
    expect(DBInstance.authenticate).toHaveBeenCalledTimes(1);
  });

  test('数据库连接失败时返回异常状态', async () => {
    // 修改authenticate为抛出错误
    (Sequelize as jest.Mock).mock.results[0].value.authenticate.mockRejectedValue(new Error('mock db error'));

    const DBInstance = (await import('../path/to/DBInstance')).default;
    const HealthContext = (await import('../path/to/HealthContext')).default;

    const healthContext = new HealthContext(DBInstance);
    const result = await healthContext.checkHealthStatus();
    expect(result).toEqual(false);
    expect(DBInstance.authenticate).toHaveBeenCalledTimes(1);
  });
});

方案二:每个测试独立Mock(jest.doMock)

使用jest.doMock替代jest.mock,它不会被提升到顶部,可在每个测试中单独定义Mock逻辑,配合动态导入确保实例使用当前测试的Mock。

测试用例代码

describe('健康检查测试', () => {
  beforeEach(() => {
    jest.resetModules(); // 重置模块缓存
  });

  test('数据库连接正常时返回健康状态', async () => {
    // 单独定义当前测试的Mock逻辑
    jest.doMock('sequelize', () => {
      const actualSequelize = jest.requireActual('sequelize');
      return {
        Sequelize: jest.fn(() => ({
          authenticate: jest.fn().mockResolvedValue(undefined)
        })),
        DataTypes: actualSequelize.DataTypes
      };
    });

    // 动态导入模块
    const DBInstance = (await import('../path/to/DBInstance')).default;
    const HealthCheck = (await import('../path/to/HealthCheck')).default;

    const healthCheck = new HealthCheck(DBInstance);
    const result = await healthCheck.checkHealthStatus();
    expect(result).toEqual(true);
  });

  test('数据库连接失败时返回异常状态', async () => {
    jest.doMock('sequelize', () => {
      const actualSequelize = jest.requireActual('sequelize');
      return {
        Sequelize: jest.fn(() => ({
          authenticate: jest.fn().mockRejectedValue(new Error('mock db error'))
        })),
        DataTypes: actualSequelize.DataTypes
      };
    });

    const DBInstance = (await import('../path/to/DBInstance')).default;
    const HealthContext = (await import('../path/to/HealthContext')).default;

    const healthContext = new HealthContext(DBInstance);
    const result = await healthContext.checkHealthStatus();
    expect(result).toEqual(false);
  });
});

关键注意事项

  • 避免提前导入业务模块:所有需要使用Mock的模块(如DBInstance、HealthCheck)必须在Mock定义后动态导入,否则会使用真实的Sequelize实例。
  • 重置模块缓存:jest.resetModules()会清除已导入模块的缓存,确保每次测试都重新加载模块并应用最新的Mock。
  • Mock保留必要的真实类型:通过jest.requireActual保留DataTypes、Dialect等真实类型,避免TypeScript类型错误。

内容的提问来源于stack exchange,提问作者jamesdeath123

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 05:45:22