【问题标题】:Sinon.restore not working for stubbing and testing AWS functionsSinon.restore 不适用于存根和测试 AWS 功能
【发布时间】:2021-03-09 10:15:57
【问题描述】:

所以我正在尝试编写一些测试来测试我一直在编写的 AWS 包装器库。 测试单独运行没有任何问题,但不会全部作为一个“描述”块运行。

const AWS_REGION = 'eu-west-2';

const aws = require('aws-sdk');
const chai = require('chai');
const expect = chai.expect;
const sinon = require('sinon');
const sinonChai = require('sinon-chai');
chai.use(sinonChai);

// These help:
// https://stackoverflow.com/questions/26243647/sinon-stub-in-node-with-aws-sdk
// https://stackoverflow.com/questions/61516053/sinon-stub-for-lambda-using-promises
describe('SQS Utilities Test', () => {

  afterEach(() => {
    sinon.restore();
  });

  it('should add to SQS', async () => {
    sinon.stub(aws.config, 'update');

    const sqs = {
      sendMessage: sinon.stub().returnsThis(),
      promise: sinon.stub()
    };
    sinon.stub(aws, 'SQS').callsFake(() => sqs);

    // these use the above stubbed version of aws
    const AWSUtilities = require('../index').AWSUtilities;
    const awsUtilities = new AWSUtilities(AWS_REGION);
    const response = await awsUtilities.postToSQS('https://example.com', { id: 1}, 'chicken');

    expect(sqs.sendMessage).to.have.been.calledOnce;
  });

  it('should get from SQS', async () => {
    sinon.stub(aws.config, 'update');

    const sqs = {
      receiveMessage: sinon.stub().returnsThis(),
      promise: sinon.stub()
    };
    sinon.stub(aws, 'SQS').callsFake(() => sqs);

    // these use the above stubbed version of aws
    const AWSUtilities = require('../index').AWSUtilities;
    const awsUtilities = new AWSUtilities(AWS_REGION);

    const response = await awsUtilities.getFromSQS('https://example.com');
    expect(sqs.receiveMessage).to.have.been.calledOnce;
  });

...

我注意到,在第二个测试中,我得到的错误是sqs.receiveMessage is not a function,这意味着第二个测试使用了第一个测试中的sqs 对象(我可以进一步验证这是错误如果我将receiveMessage 添加到第一个测试sqs 对象,则会发生变化。

这是sinon restore中的错误,还是我写错了?这是整个库:https://github.com/unegma/aws-utilities/blob/main/test/SQSTests.spec.js

【问题讨论】:

  • 这行:github.com/unegma/aws-utilities/blob/… (const sqs) 必须在那里定义吗?这就是诗乃无法恢复的原因。您可以在其中的每个 require 函数中使用 rewire for require;如果您不想更改 AWSUtilities 实施。
  • 似乎是因为您在测试文件与索引文件中存根不同的 aws 包。您能在此处发布您的索引/AWSUtilities 文件吗?
  • 你能把正在测试的代码贴出来吗?

标签: node.js amazon-web-services testing aws-sdk sinon


【解决方案1】:

这不是诗乃的问题。这是您如何存根 AWS 开发工具包的问题。让我们分解您共享的代码中发生的事情。

const sqs = {
  sendMessage: sinon.stub().returnsThis(),
  promise: sinon.stub()
};
sinon.stub(aws, 'SQS').callsFake(() => sqs);

// these use the above stubbed version of aws
const AWSUtilities = require('../index').AWSUtilities;

此代码执行以下操作

  1. 存根SQS of aws。
  2. 加载AWSUtilities.js(基于github中的源代码)

AWSUtilities.js 在加载后立即执行以下操作

const aws = require('aws-sdk');
const sqs = new aws.SQS();

// code removed to demo the concept

上面的代码创建了一个内部sqs 对象,在本例中是使用存根的aws 模块创建的。在节点中,一旦使用require 加载模块,它就会缓存在内存中,即上面的代码只执行一次。

所以当第一个it() 执行时,它会依次加载AWSUtilities.js 并被缓存。任何后续调用都会获取缓存版本。当您调用sinon.restore 时,它只会恢复aws 模块的SQS 函数,它不会恢复在AWSUtilities.js 中创建的sqs 对象。

我希望这可以解释您所看到的行为的原因。

有多种方法可以解决此问题。依赖注入,在所有测试用例之前使用 proxyquire、rewire、stubbing aws 等模块。

以下是仅在此处显示的测试用例中修复它的选项。

describe('SQS Utilities Test', () => {
  let AWSUtilities, sqsStub;

  before(() => {
    sinon.stub(aws.config, 'update');

    sqsStub = {
      sendMessage: sinon.stub().returnsThis(),
      receiveMessage: sinon.stub().returnsThis(),
      promise: sinon.stub()
    };
    sinon.stub(aws, 'SQS').callsFake(() => sqs);
    AWSUtilities = require('../index').AWSUtilities;
  });

  after(() => {
    sinon.restore();
  });

  it('should add to SQS', async () => {
    const awsUtilities = new AWSUtilities(AWS_REGION);
    const response = await awsUtilities.postToSQS('https://example.com', { id: 1}, 'chicken');
    expect(sqsStub.sendMessage).to.have.been.calledOnce;
  });

  it('should get from SQS', async () => {
    const awsUtilities = new AWSUtilities(AWS_REGION);
    const response = await awsUtilities.getFromSQS('https://example.com');
    expect(sqsStub.receiveMessage).to.have.been.calledOnce;
  });
});

【讨论】:

  • 嗨,感谢您非常彻底的回答,我真的很感激,我没有意识到它是如何工作的。我想将 sqsStub 本身添加到it('should' 函数的原因是,我可以为每个存根函数(例如sendMessage)的returnsThis 语句创建独特的行为(例如不同的返回值)。看起来我必须找到更好的方法来做到这一点,我会尝试类似sqsStub = { ...sqsStub, sendMessage: ...returns...} 的方法,看看会发生什么。再次感谢!
猜你喜欢
  • 2014-06-09
  • 1970-01-01
  • 2015-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-27
相关资源
最近更新 更多