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

如何使用Jest模拟Sequelize事务?

问题分析与解决方案

你的测试失败源于两个核心问题:

  • 直接修改sequelize.transaction的模拟方式未覆盖到doSomething函数中导入的sequelize实例,导致实际调用的仍是原方法而非模拟函数
  • 你给sequelize.transaction赋值的默认jest.fn()不会执行传入的异步回调,内部的upsert自然不会被触发

正确的测试用例实现

1. 模块级模拟依赖

使用Jest的模块模拟功能,确保替换的依赖能被doSomething正确引用:

// 模拟sequelize模块,让transaction执行传入的异步回调
jest.mock('../path/to/sequelize', () => {
  const mockTransaction = jest.fn(async (callback) => {
    // 传入模拟的transaction对象执行回调
    return callback({});
  });
  return {
    transaction: mockTransaction,
    define: jest.fn() // 模型定义所需的模拟方法
  };
});

// 模拟customModel模块
jest.mock('../path/to/customModel', () => ({
  upsert: jest.fn().mockResolvedValue(true)
}));

// 模拟otherCustomModel模块
jest.mock('../path/to/otherCustomModel', () => ({
  upsert: jest.fn().mockResolvedValue(true)
}));

// 导入待测试函数与模拟依赖
import { doSomething } from '../path/to/doSomething';
import sequelize from '../path/to/sequelize';
import customModel from '../path/to/customModel';
import otherCustomModel from '../path/to/otherCustomModel';

// 测试前清理模拟状态,避免用例污染
beforeEach(() => {
  jest.clearAllMocks();
});

test('doSomething执行事务与upsert逻辑正确', async () => {
  await doSomething();

  // 断言transaction被调用一次,且传入异步回调
  expect(sequelize.transaction).toHaveBeenCalledTimes(1);
  expect(typeof sequelize.transaction.mock.calls[0][0]).toBe('function');

  // 断言两个upsert各被调用一次,且携带transaction参数
  expect(customModel.upsert).toHaveBeenCalledTimes(1);
  expect(otherCustomModel.upsert).toHaveBeenCalledTimes(1);
  expect(customModel.upsert.mock.calls[0][1]).toHaveProperty('transaction');
  expect(otherCustomModel.upsert.mock.calls[0][1]).toHaveProperty('transaction');
});

2. 异步逻辑处理

注意doSomething内部使用了异步事务回调,测试函数需标记为async并await doSomething(),确保所有异步逻辑执行完成后再做断言。

测试用例优化建议

  • 异常场景覆盖:测试事务回调抛出错误时的逻辑,验证事务是否按预期处理:
    test('doSomething处理事务失败场景', async () => {
      sequelize.transaction = jest.fn(async () => {
        throw new Error('事务执行失败');
      });
    
      await expect(doSomething()).rejects.toThrow('事务执行失败');
      // 可根据业务逻辑断言第二个upsert是否被调用
      expect(otherCustomModel.upsert).not.toHaveBeenCalled();
    });
    
  • 参数正确性验证:如果dataObject是可预测的,可断言upsert的传入参数是否符合预期:
    const expectedData = { id: 1, name: 'test' };
    // 假设doSomething内部使用该数据
    expect(customModel.upsert).toHaveBeenCalledWith(expectedData, expect.any(Object));
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 03:47:48