问题描述
我正在尝试模拟 AWS Secrets Manager 的 getSecretValue
方法。
它不起作用 - 它没有调用 sinon
模拟,而是调用真正的 AWS 函数。
示例测试:
'use strict';
const sinon = require( 'sinon' );
const AWS = require( 'aws-sdk' );
const secretsManager = new AWS.SecretsManager();
const unitUnderTest = require( '../modules/myUnitUnderTest' );
const { expect } = require( 'chai' );
describe( 'Failing example for Stack Overflow',async () => {
afterEach( () => {
sinon.restore();
} );
it( 'mocks the call to AWS Secret Manager successfully',async () => {
sinon.stub( secretsManager,'getSecretValue' ).returns( Promise.resolve( {SecretString: { publicKey: 'secretUsername',privateKey: 'secretPassword' }} ) );
const key = 'key';
const username = null;
const password = null;
await unitUnderTest( key,username,password );
expect( username ).to.equal( 'secretUsername' );
expect( password ).to.equal( 'secretPassword' );
} );
} );
示例函数:
const AWS = require( 'aws-sdk' );
const secretsManager = new AWS.SecretsManager();
module.exports = async ( keyId,password ) => {
await getSecret( keyId )
.then( secret => {
username = secret.publicKey;
password = secret.privateKey;
} )
.catch(
err => {
logger.error( err );
}
);
};
const getSecret = (keyId ) => {
return new Promise( ( resolve,reject ) => {
secretsManager.getSecretValue( {
SecretId: keyId
},( err,data ) => {
if ( err ) {
reject( err );
} else {
resolve( JSON.parse( data.SecretString ) );
}
} );
} );
};
预期行为:
Sinon 嘲笑 AWS Secrets Manager
实际行为:
Sinon 不起作用,AWS 被真正调用,我的日志中出现错误,证明真实的 AWS 开发工具包已被调用/已尝试从 AWS Secrets Manager 帐户中读取我的默认配置文件中的秘密机器:
Failed to obtain the secret: ConfigError: Missing region in config
我对此无能为力。为什么 sinon 不起作用?
解决方法
由于您在模块范围内实例化 AWS.SecretsManager
,因此您需要在需要您的模块之前存根 AWS.SecretsManager
类。
例如
main.js
:
const AWS = require('aws-sdk');
const secretsManager = new AWS.SecretsManager();
module.exports = async (keyId) => {
return getSecret(keyId)
.then((secret) => {
const username = secret.publicKey;
const password = secret.privateKey;
return { username,password };
})
.catch((err) => {
console.error(err);
});
};
const getSecret = (keyId) => {
return new Promise((resolve,reject) => {
secretsManager.getSecretValue(
{
SecretId: keyId,},(err,data) => {
if (err) {
reject(err);
} else {
resolve(JSON.parse(data.SecretString));
}
},);
});
};
main.test.js
:
const AWS = require('aws-sdk');
const sinon = require('sinon');
const { expect } = require('chai');
describe('67322634',() => {
afterEach(() => {
sinon.restore();
});
it('should get secret value',async () => {
const data = {
SecretString: JSON.stringify({ publicKey: 'secretUsername',privateKey: 'secretPassword' }),};
const secretsManagerStub = {
getSecretValue: sinon.stub().callsFake((params,callback) => {
callback(null,data);
}),};
const SecretsManagerStub = sinon.stub(AWS,'SecretsManager').returns(secretsManagerStub);
const main = require('./main');
const { username,password } = await main('1');
expect(username).to.equal('secretUsername');
expect(password).to.equal('secretPassword');
sinon.assert.calledOnce(SecretsManagerStub);
sinon.assert.calledOnceWithExactly(
secretsManagerStub.getSecretValue,{
SecretId: '1',sinon.match.func,);
});
});
单元测试结果:
67322634
✓ should get secret value (1472ms)
1 passing (1s)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 85.71 | 50 | 83.33 | 85.71 |
main.js | 85.71 | 50 | 83.33 | 85.71 | 12,24
----------|---------|----------|---------|---------|-------------------