为何Sinon Stub未生效仍发起AWS外部调用?JS Lambda测试问题
AWS Lambda单元测试中Sinon Stub失效问题排查
业务代码(index.js)
// index.js const AWS = require("aws-sdk"); const getParam = async (path) => { const ssm = new AWS.SSM(); const params = { Name: path, WithDecryption: false } // 原代码存在笔误:param应为params const result = await ssm.getParameter(params).promise(); const value = result['Parameter']['Value'] console.log("@@", value); return value; } module.exports = { getParam }; // 需补充导出,否则测试无法引入
原测试代码(index.test.js)
// index.test.js const AWS = require("aws-sdk"); AWS.config.update({ region: 'us-east-1' }); const chai = require('chai'); const expect = chai.expect; const sinon = require("sinon"); const { getParam } = require('./index.js'); describe("test1", () => { // 语法错误:用if替代了Mocha的it测试用例语法 if('testing', async () => { // 错误1:创建实例时少了new;错误2:该实例与业务代码内新建的实例完全独立 const ssm = AWS.SSM(); // 参数匹配错误:指定匹配"testing",但实际调用传入的是"Hello" sinon.stub(ssm, "getParameter").withArgs("testing") .resolve({ Parameter: { Value: "TESTING VALUE FROM PARAM STORE" } }); const res = await getParam("Hello"); console.log(res); // 断言无效:未验证实际返回值,仅对比两个相同字符串 expect("TESTING VALUE FROM PARAM STORE").to.equal("TESTING VALUE FROM PARAM STORE"); }) })
问题分析
导致Stub失效、触发真实AWS调用的核心原因:
- Stub对象不匹配:测试中Stub的是局部创建的
ssm实例,但业务代码每次调用getParam都会新建new AWS.SSM()实例,两个实例完全独立,Stub无法作用到业务代码的实例。 - 语法与参数错误:用
if替代it导致测试逻辑异常;Stub指定的匹配参数与实际调用参数不符,导致Stub不触发。 - 业务代码笔误:
getParameter(param)中的param应为定义好的params,会导致运行时参数错误。 - 断言无效:未验证函数实际返回值,无法发现逻辑问题。
修正后的测试代码
// index.test.js const AWS = require("aws-sdk"); const chai = require('chai'); const expect = chai.expect; const sinon = require("sinon"); const { getParam } = require('./index.js'); describe("getParam函数测试", () => { let ssmStub; // 每个测试前Stub SSM类的原型方法,确保所有实例都使用Stub beforeEach(() => { ssmStub = sinon.stub(AWS.SSM.prototype, "getParameter"); }); // 测试后恢复Stub,避免影响其他测试 afterEach(() => { ssmStub.restore(); }); it("应正确获取模拟的SSM参数值", async () => { const mockValue = "TESTING VALUE FROM PARAM STORE"; const testPath = "Hello"; // 模拟AWS SDK的promise链式调用 ssmStub.returns({ promise: () => Promise.resolve({ Parameter: { Value: mockValue } }) }); const res = await getParam(testPath); // 验证getParameter是否被传入正确参数 sinon.assert.calledWith(ssmStub, { Name: testPath, WithDecryption: false }); // 断言返回值符合预期 expect(res).to.equal(mockValue); }); })
关键修正说明
- Stub原型方法:通过
sinon.stub(AWS.SSM.prototype, "getParameter")Stub类的原型方法,确保所有new AWS.SSM()创建的实例都会使用该Stub。 - 处理promise链式调用:AWS SDK方法返回带
.promise()的对象,因此Stub需返回包含promise方法的对象,该方法返回resolved状态的Promise。 - 验证调用参数:用
sinon.assert.calledWith校验参数组装是否正确,确保业务逻辑符合预期。 - 有效断言:直接验证函数返回值,确保逻辑正确性。
内容的提问来源于stack exchange,提问作者Gwenda Thomas
相关产品推荐
相关产品推荐

