Sinon.restore funktioniert nicht zum Stubben und Testen von AWS-Funktionen

Nov 26 2020

Ich versuche also, ein paar Tests zum Testen einer AWS-Wrapper-Bibliothek zu schreiben, die ich geschrieben habe. Die Tests werden einzeln ohne Probleme ausgeführt, aber nicht alle werden als ein "Beschreibungsblock" ausgeführt.

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;
  });

...

Was ich aufgefallen ist, dass in dem zweiten Test, der Fehler I bin immer sqs.receiveMessage is not a function, was bedeutet , dass der zweite Test des verwendete sqsObjekt aus dem ersten Test (ich dies als Fehler Änderungen weiter verifizieren kann , wenn ich hinzufügen , receiveMessagemit dem ersten sqsTestobjekt ).

Ist dies ein Fehler bei der Sinon-Wiederherstellung oder habe ich etwas falsch geschrieben? Hier ist die ganze Bibliothek:https://github.com/unegma/aws-utilities/blob/main/test/SQSTests.spec.js

Antworten

1 Josnidhin Dec 16 2020 at 10:59

Dies ist kein Problem mit Sinon. Dies ist eine Frage, wie Sie das AWS SDK stubben. Lassen Sie uns zusammenfassen, was in dem von Ihnen freigegebenen Code passiert.

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;

Dieser Code führt Folgendes aus

  1. Stummel SQSvon aws.
  2. Laden AWSUtilities.js(basierend auf dem Quellcode in Github)

AWSUtilities.js führt Folgendes aus, sobald es geladen ist

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

// code removed to demo the concept

Der obige Code erstellt ein internes sqsObjekt, das in diesem Fall mit dem stubbed aws-Modul erstellt wird. Sobald ein Modul im Knoten geladen wurde, wird requirees im Speicher zwischengespeichert, dh der obige Code wird nur einmal ausgeführt.

Wenn der erste it()ausgeführt wird, wird er wiederum AWSUtilities.jszum ersten Mal geladen und zwischengespeichert. Alle nachfolgenden Aufrufe erhalten die zwischengespeicherte Version. Wenn Sie es aufrufen sinon.restore, wird nur die SQSFunktion des awsModuls wiederhergestellt, und das darin erstellte sqsObjekt wird nicht wiederhergestellt AWSUtilities.js.

Ich hoffe, das erklärt den Grund für das Verhalten, das Sie sehen.

Es gibt mehrere Möglichkeiten, um dieses Problem zu beheben. Abhängigkeitsinjektion unter Verwendung von Modulen wie Proxyquire, Neuverdrahtung, Stubbing von Aws von einer zentralen Stelle vor allen Testfällen usw.

Das Folgende ist eine Option, um das Problem nur in den hier gezeigten Testfällen zu beheben.

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;
  });
});