TypeError:AWS.SecretsManager 不是使用 proxyquire 进行单元测试的构造函数

Posted

技术标签:

【中文标题】TypeError:AWS.SecretsManager 不是使用 proxyquire 进行单元测试的构造函数【英文标题】:TypeError: AWS.SecretsManager is not a constructor in unit testing with proxyquire 【发布时间】:2021-12-14 04:48:55 【问题描述】:

我编写了一个测试代码来测试从 AWS Secret Manager 提供凭证的代码。我使用 proxyquire 和 sinon 来存根并得到这个错误。

我要测试的函数

    exports.getCredsFromAWSSecretsManager = (keyName) => 
    const SM = new AWS.SecretsManager(
        apiVersion: process.env.AWS_SM_API_VERSION,
        region: process.env.AWS_SM_REGION
    );

    return SM.getSecretValue(params).promise().then((data) => 
        logger.info(logMsgs.awsHlpr_smGetSecretValueSuccess(JSON.stringify(data)));
        return JSON.parse(data.SecretString);
        
    ).catch((err) => 
        logger.error(logMsgs.awsHlpr_smGetSecretValueErr(JSON.stringify(err)));
        throw err;
    );
;

我写的测试用例

const sinon = require("sinon");
const proxyquire = require("proxyquire").noCallThru().noPreserveCache();
const  mockLogger  = require("../../mockdata/mockLogger");

let awsHelper;
let secretsManagerStub;

describe.only("AWS Helper ", () => 

    // function1

    describe("AWS Helper: getCredsFromAWSSecretsManagera method", () => 

        before((done) => 
            const data = 
                SecretString: JSON.stringify( publicKey: 'secretUsername', privateKey: 'secretPassword' ),
              ;
            
            secretsManagerStub = 
                getSecretValue: sinon.stub().callsFake((params, callback) => 
                  callback(null, data);
                ),
               
              ;

            const awsStub = 
                
                  SecretsManager: sinon.stub().returns(secretsManagerStub)
               
                
             
            awsHelper = proxyquire('../../../utils/aws_helper.js', 
                'aws-sdk':
                    AWS:awsStub
                 ,
                 "../../utils/logger": mockLogger,
            ); 
            
              

            done();
        );

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

        it('should write random data!', async () => 

            const expectedData = "abcdef";

            secretsManagerStub.getSecretValue.yields(null, expectedData);

            const data = await awsHelper.getCredsFromAWSSecretsManager();

            sinon.assert.callCount(secretsManagerStub.getSecretValue, 1);
            assert.strictEqual(data, expectedData);
            
        );

    );
);

这段代码给了我错误信息 TypeError:AWS.SecretsManager 不是构造函数

任何帮助将不胜感激。

【问题讨论】:

【参考方案1】:

AWS 是一个命名空间,它包含所有 AWS 服务类,例如 SecretsManager。您应该将awsStub 提供给aws-sdk,无需将awsStub 包装在对象中。

aws_helper.js:

const AWS = require('aws-sdk');

exports.getCredsFromAWSSecretsManager = () => 
  const SM = new AWS.SecretsManager(
    apiVersion: process.env.AWS_SM_API_VERSION,
    region: process.env.AWS_SM_REGION,
  );
  const params = 
    SecretId: '1',
  ;

  return SM.getSecretValue(params)
    .promise()
    .then((data) => 
      console.info(data);
      return JSON.parse(data.SecretString);
    )
    .catch((err) => 
      console.error(err);
      throw err;
    );
;

aws_helper.test.js:

const sinon = require('sinon');
const proxyquire = require('proxyquire').noCallThru().noPreserveCache();

let awsHelper;
let secretsManagerStub;

describe('AWS Helper: getCredsFromAWSSecretsManagera method', () => 
  before(() => 
    const data = 
      SecretString: JSON.stringify( publicKey: 'secretUsername', privateKey: 'secretPassword' ),
    ;

    secretsManagerStub = 
      getSecretValue: sinon.stub().returnsThis(),
      promise: sinon.stub().resolves(data),
    ;

    const awsStub = 
      SecretsManager: sinon.stub().returns(secretsManagerStub),
    ;
    awsHelper = proxyquire('./aws_helper.js', 
      'aws-sdk': awsStub,
    );
  );

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

  it('should write random data!', async () => 
    const data = await awsHelper.getCredsFromAWSSecretsManager();
    sinon.assert.callCount(secretsManagerStub.getSecretValue, 1);
    sinon.assert.match(data,  publicKey: 'secretUsername', privateKey: 'secretPassword' );
  );
);

测试结果:

  AWS Helper: getCredsFromAWSSecretsManagera method

  SecretString: '"publicKey":"secretUsername","privateKey":"secretPassword"'

    ✓ should write random data!


  1 passing (2s)

---------------|---------|----------|---------|---------|-------------------
File           | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
---------------|---------|----------|---------|---------|-------------------
All files      |   77.78 |      100 |   66.67 |   77.78 |                   
 aws_helper.js |   77.78 |      100 |   66.67 |   77.78 | 19-20             
---------------|---------|----------|---------|---------|-------------------

【讨论】:

非常感谢。现在可以了。我能知道我们为什么要在函数内部定义参数吗?有什么办法不改变功能代码。对不起,我不擅长 AWS 服务 @SanjanaEkanayake params?我没有从您的代码中看到此变量,因此我创建了一个以使代码可执行。重点是演示测试

以上是关于TypeError:AWS.SecretsManager 不是使用 proxyquire 进行单元测试的构造函数的主要内容,如果未能解决你的问题,请参考以下文章

反应本机获取多标记[未处理的承诺拒绝:TypeError:TypeError:未定义不是对象(评估'this.state.markers.map

Django TypeError - TypeError: issubclass() arg 1 必须是一个类

pyspark:TypeError:'float'对象不可迭代

Python 3.8 TypeError: can't concat str to bytes - TypeError: a bytes-like object is required, not 's

TypeError: key 必须是一个字符串,一个缓冲区或一个对象在 typeError 与 GCP 文件存在

TypeError: jQueryxxxxxx 不是函数