Sinon.restore nie działa do tworzenia kodów kreskowych i testowania funkcji AWS
Więc próbuję napisać kilka testów do testowania biblioteki AWS, którą pisałem. Testy przebiegają indywidualnie bez żadnych problemów, ale nie wszystkie będą działały jako jeden blok „opisywania”.
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;
});
...
Zauważyłem, że w drugim teście otrzymuję błąd sqs.receiveMessage is not a function
, co oznacza, że drugi test wykorzystuje sqs
obiekt z pierwszego testu (mogę to dalej zweryfikować, ponieważ błąd się zmienia, jeśli dodam receiveMessage
do pierwszego sqs
obiektu testu ).
Czy to błąd w przywracaniu sinon, czy może napisałem coś niepoprawnie? Oto cała biblioteka:https://github.com/unegma/aws-utilities/blob/main/test/SQSTests.spec.js
Odpowiedzi
To nie jest problem z Sinonem. To kwestia sposobu, w jaki korzystasz z pakietu AWS SDK. Podzielmy się tym, co dzieje się w udostępnionym kodzie.
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;
Ten kod wykonuje następujące czynności
- Stub
SQS
zaws
. - Załaduj
AWSUtilities.js
(na podstawie kodu źródłowego w github)
AWSUtilities.js
wykonuje następujące czynności zaraz po załadowaniu
const aws = require('aws-sdk');
const sqs = new aws.SQS();
// code removed to demo the concept
Powyższy kod tworzy wewnętrzny sqs
obiekt, który w tym przypadku jest tworzony za pomocą modułu stubbed aws. W węźle po załadowaniu modułu przy użyciu require
jego buforowania w pamięci, tj. Powyższy kod jest wykonywany tylko raz.
Więc kiedy pierwszy it()
wykonuje, to z kolei ładuje AWSUtilities.js
się po raz pierwszy i jest buforowany. Każde kolejne wywołanie otrzymuje wersję z pamięci podręcznej. Kiedy wywołujesz sinon.restore
, przywraca tylko SQS
funkcję aws
modułu, nie przywraca sqs
obiektu, który został utworzony w środku AWSUtilities.js
.
Mam nadzieję, że to wyjaśnia powód zachowania, które widzisz.
Istnieje wiele sposobów rozwiązania tego problemu. Wstrzykiwanie zależności, używanie modułów takich jak proxyquire, rewire, stubbing aws z centralnej lokalizacji przed wszystkimi przypadkami testowymi itp.
Poniżej znajduje się opcja naprawienia tego problemu tylko w pokazanych tutaj przypadkach testowych.
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;
});
});