如何使用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
相关产品推荐
相关产品推荐

