Sinon.restore no funciona para realizar copias de seguridad y probar funciones de AWS
Así que estoy tratando de escribir algunas pruebas para probar una biblioteca contenedora de AWS que he estado escribiendo. Las pruebas se ejecutan individualmente sin ningún problema, pero no todas se ejecutarán como un bloque de 'descripción'.
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;
});
...
Lo que noté es que en la segunda prueba, el error que obtengo es sqs.receiveMessage is not a function
, lo que significa que la segunda prueba está usando el sqs
objeto de la primera prueba (puedo verificar esto aún más a medida que el error cambia si agrego receiveMessage
al primer sqs
objeto de prueba ).
¿Es esto un error en Sinon restore o he escrito algo incorrectamente? Aquí está toda la biblioteca:https://github.com/unegma/aws-utilities/blob/main/test/SQSTests.spec.js
Respuestas
Este no es un problema con Sinon. Se trata de una cuestión de cómo se almacena AWS SDK. Analicemos lo que está sucediendo dentro del código que ha compartido.
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;
Este código hace lo siguiente
- Trozo
SQS
deaws
. - Cargar
AWSUtilities.js
(basado en el código fuente en github)
AWSUtilities.js
hace lo siguiente tan pronto como se carga
const aws = require('aws-sdk');
const sqs = new aws.SQS();
// code removed to demo the concept
El código anterior crea un sqs
objeto interno , que en este caso se crea utilizando el módulo aws stubped. En el nodo, una vez que se carga un módulo utilizando require
su caché en la memoria, es decir, el código anterior se ejecuta solo una vez.
Entonces, cuando el primero lo it()
ejecuta, a su vez se carga AWSUtilities.js
por primera vez y se almacena en caché. Cualquier llamada posterior obtiene la versión en caché. Cuando lo llamas sinon.restore
, solo restaura la SQS
función del aws
módulo, no restaura el sqs
objeto que se creó dentro AWSUtilities.js
.
Espero que eso explique la razón del comportamiento que está viendo.
Hay varias formas de solucionar este problema. Inyección de dependencias, utilizando módulos como proxyquire, rewire, stubbing aws desde una ubicación central antes de todos los casos de prueba, etc.
La siguiente es una opción para solucionarlo solo en los casos de prueba que se muestran aquí.
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;
});
});