如何修改jest.mock返回值 模拟aws-sdk SQS接口报错测试场景
问题根因
你当前的逻辑有三个核心问题,导致错误分支无法覆盖:
- 你写的
changeMessageVisibility: jest.fn().mockReturnValue( {} )只是模拟了方法的同步返回值,完全没有执行调用时传入的第二个回调参数,不管成功、失败的回调逻辑都不会触发,自然进不到错误分支。 - 测试用例里监听的是
console.error,但你的业务代码错误分支用的是console.log打印日志,就算回调触发了也会因为监听对象不对导致断言失败。 - 至于
jest.mock写在describe、beforeAll里失效,是Jest本身的机制导致:Jest编译阶段会自动把所有jest.mock调用提升到文件最顶部,写在块级作用域里会因为作用域提升不符合预期导致mock失效,固定把jest.mock写在文件顶部即可。
方案1:直接调整现有mock逻辑支持回调触发
不需要大改业务代码,只要调整mock实现,让它主动执行传入的回调即可。
首先修改顶部的基础mock,默认模拟接口调用成功的场景:
jest.mock('aws-sdk', () => { const SQSMocked = { // 接收入参,第二个参数就是业务代码传的回调,默认传null作为错误值代表成功 changeMessageVisibility: jest.fn((params, callback) => callback(null, {})), }; const configMocked = { update: jest.fn().mockReturnThis() } return { SQS: jest.fn(() => SQSMocked), config: configMocked }; });
在测试错误场景的用例里,临时修改mock实现,给回调传入错误对象即可,记得用例执行完还原mock避免影响其他用例:
test("changeMessageVisibility调用失败时会打印错误日志", async () => { // 缓存原有mock实现,测完还原 const originalImpl = sqs.changeMessageVisibility.getMockImplementation(); // 注意这里要spy console.log,和业务代码保持一致 const logSpy = jest.spyOn(console, 'log').mockImplementation(() => null); const testError = new Error('SQS change visibility timeout failed'); // 临时模拟接口报错 sqs.changeMessageVisibility.mockImplementationOnce((params, callback) => { callback(testError, null); }); await ingest.retryIngest(TEST_CONSTANTS.sqsIngestEventMessageWithTwoRecords); // 断言日志打印逻辑被触发 expect(logSpy).toHaveBeenCalledTimes(1); expect(logSpy).toHaveBeenCalledWith(testError, testError.stack); // 清理现场 logSpy.mockRestore(); sqs.changeMessageVisibility.mockImplementation(originalImpl); })
方案2:重构业务代码降低测试成本
AWS SDK原生支持Promise形式的调用,比回调写法更易维护、更好mock,推荐把业务代码改成Promise+async/await的写法:
try { await sqs.changeMessageVisibility({ QueueUrl: sourceQueueURL, ReceiptHandle: record.receiptHandle, VisibilityTimeout: camera.ingest.retryIntr }).promise(); } catch (err) { console.log(err, err.stack); }
重构后mock逻辑更简单,不需要手动处理回调参数,模拟成功就返回resolve的promise,模拟失败就返回rejected的promise即可,错误场景的mock可以简化为:
const testError = new Error('SQS request failed'); sqs.changeMessageVisibility.mockReturnValueOnce({ promise: jest.fn().mockRejectedValue(testError) });
这种写法完全规避了回调参数处理的问题,代码可读性也更高。
内容的提问来源于stack exchange,提问作者lowcrawler
相关产品推荐
相关产品推荐

