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

Jest中Mock AWS SDK的SQS.receiveMessage方法失效问题排查

问题:Jest模拟AWS SQS receiveMessage方法仅局部生效

业务代码:sqsHelper.js

const AWS = require("aws-sdk");

export default class SqsHelper {
  static SqsGetMessagesTest = () => {
    const sqs = new AWS.SQS({
      apiVersion: serviceConfig.sqs.api_version,
      region: serviceConfig.sqs.region,
    });

    const queueURL = "https://sqs.us-west-2.amazonaws.com/<1234>/<4567>";

    const params = {
      AttributeNames: ["SentTimestamp"],
      MaxNumberOfMessages: 10,
      MessageAttributeNames: ["All"],
      QueueUrl: queueURL,
      VisibilityTimeout: 20,
      WaitTimeSeconds: 20,
    };

    return new Promise((resolve, reject) => {
      sqs.receiveMessage(params, async (recErr, recData) => {
        if (recErr) {
          reject(recErr);
        } else if (recData.Messages) {
          console.info(`Message count: ${recData.Messages.length}`);
          resolve(recData.Messages);
        }
      });
    });
  };
}

测试代码:sqsHelper.test.js

import SqsHelper from "../../helpers/sqsHelper.js";
import { SQS } from "aws-sdk";

const dumyData = { Messages: [{ name: "123", lastName: "456" }] };
const sqs = new SQS();

describe("Test SQS helper", () => {
  test("Recieve message", async () => {
    jest.spyOn(sqs, 'receiveMessage').mockReturnValue(dumyData);

    // check 1
    const res1 = await sqs.receiveMessage();
    console.log(`res: ${JSON.stringify(res1, null, 2)}`)
    expect(res1).toEqual(dumyData);

    // check 2
    const res2 = await SqsHelper.SqsGetMessagesTest();
    console.log(`res2: ${JSON.stringify(res2, null, 2)}`);
    expect(res2).toBe(dumyData);
  });
});

问题现象

测试中直接调用模拟后的sqs.receiveMessage方法能正常返回假数据,但调用SqsHelper.SqsGetMessagesTest方法时,模拟未生效,触发真实请求并报错:InvalidClientTokenId: The security token included in the request is invalid.


问题原因

  1. 你仅对测试文件内局部创建的sqs实例做了模拟,但业务代码里是通过new AWS.SQS()创建了全新的独立实例,这个新实例未被Jest拦截,因此会发起真实API请求。
  2. receiveMessage采用回调式调用,直接返回dummyData不符合它的调用逻辑,无法触发业务代码里的回调处理。

修复后的测试代码

import SqsHelper from "../../helpers/sqsHelper.js";
import AWS from "aws-sdk";

const dummyData = { Messages: [{ name: "123", lastName: "456" }] };

describe("Test SQS helper", () => {
  let receiveMessageMock;

  beforeEach(() => {
    // 模拟AWS.SQS构造函数,让所有new出来的实例都带mock方法
    receiveMessageMock = jest.fn((params, callback) => {
      // 适配业务代码的回调逻辑,传入成功数据
      callback(null, dummyData);
    });
    jest.spyOn(AWS, "SQS").mockImplementation(() => ({
      receiveMessage: receiveMessageMock
    }));

    // 若serviceConfig是外部依赖,需同步模拟(示例)
    // jest.mock('../../path/to/serviceConfig', () => ({
    //   sqs: { api_version: '2012-11-05', region: 'us-west-2' }
    // }));
  });

  afterEach(() => {
    // 清理mock,避免污染其他测试用例
    jest.restoreAllMocks();
  });

  test("Receive message", async () => {
    const result = await SqsHelper.SqsGetMessagesTest();
    
    // 注意:业务代码resolve的是recData.Messages,而非整个dummyData
    expect(result).toEqual(dummyData.Messages);
    
    // 验证receiveMessage是否按预期调用
    expect(receiveMessageMock).toHaveBeenCalledTimes(1);
    expect(receiveMessageMock).toHaveBeenCalledWith(
      expect.objectContaining({
        QueueUrl: "https://sqs.us-west-2.amazonaws.com/<1234>/<4567>",
        MaxNumberOfMessages: 10
      }),
      expect.any(Function)
    );
  });
});

关键改动说明

  • 全局拦截SQS实例创建:通过mockAWS.SQS构造函数,让业务代码里所有new AWS.SQS()生成的实例都带有模拟方法。
  • 适配回调调用逻辑:模拟receiveMessage时主动触发回调函数,匹配业务代码的异步处理逻辑。
  • 修正断言逻辑:业务代码最终返回的是recData.Messages,断言需对应这个值而非完整的dummyData。
  • 增加mock清理:用afterEach恢复所有mock,避免影响其他测试用例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 13:50:27