用于JavaScript jest单元测试的模拟机密管理器模块

用于JavaScript jest单元测试的模拟机密管理器模块,javascript,amazon-web-services,unit-testing,jestjs,aws-secrets-manager,Javascript,Amazon Web Services,Unit Testing,Jestjs,Aws Secrets Manager,我很难在jest单元测试中模拟AWS机密管理器模块。。。它出错的部分是.promise()。当我删除它时,代码对真正的机密管理器不起作用,所以我认为它需要留在那里。如何模拟getSecretData函数,以便getSecretData.promise()可以用于模拟 下面是SecretsManager.js代码: import AWS from 'aws-sdk'; export class SecretsManager { constructor() { AWS.config.u

我很难在jest单元测试中模拟AWS机密管理器模块。。。它出错的部分是.promise()。当我删除它时,代码对真正的机密管理器不起作用,所以我认为它需要留在那里。如何模拟getSecretData函数,以便getSecretData.promise()可以用于模拟

下面是SecretsManager.js代码:

import AWS from 'aws-sdk';

export class SecretsManager {
  constructor() {
    AWS.config.update({
      region: 'us-east-1',
    });
    this.secretsManager = new AWS.SecretsManager();
  }

  async getSecretData(secretName) {
    try {
      const response = await this.secretsManager.getSecretValue({
        SecretId: secretName,
      }).promise();
      const secretString = response.SecretString;
      const parsedSecret = JSON.parse(secretString);
      return parsedSecret;
    } catch (e) {
      console.log('Failed to get data from AWS Secrets Manager.');
      console.log(e);
      throw new Error('Unable to retrieve data.');
    }
  }
}

下面是SecretsManager.test.js代码:

import { SecretsManager } from '../utils/SecretsManager';

jest.mock('aws-sdk', () => {
  return {
    config: {
      update(val) {

      },
    },
    SecretsManager: function () {
      return {
        async getSecretValue({
          SecretId: secretName
        }) {
          return {
            promise: function () {
              return {
                 UserName: 'test',
                 Password: 'password',
              };
            }
          };
        }
      };
    }
  }

});


describe('SecretsManager.js', () => {
  describe('Given I have a valid secret name', () => {
    describe('When I send a request for test_creds', () => {
      it('Then the correct data is returned.', async () => {
        const mockReturnValue = {
          UserName: 'test',
          Password: 'password',
        };
        const logger = getLogger();
        const secretManager = new SecretsManager();
        const result = await secretManager.getSecretData('test_creds');
        expect(result).toEqual(mockReturnValue)
      });
    });
    describe('When I send a request without data', () => {
      it('Then an error is thrown.', async () => {
      const secretManager = new SecretsManager();
      await expect(secretManager.getSecretData()).rejects.toThrow();
      });
    });
  });
});

这是我在运行测试时遇到的错误:

 this.secretsManager.getSecretValue(...).promise is not a function
非常感谢您的任何建议或指点

谢谢你看我的帖子。

我终于让它工作了。。。我想这会在发帖后很快发生,但我不会删除帖子,而是会分享我是如何更改mock的,以使它在帮助其他人的情况下发挥作用的

注意:这只是更新的模拟,测试与上面的问题相同

// I added this because it's closer to how AWS returns data for real.
const mockSecretData = {
  ARN: 'x',
  Name: 'test_creds',
  VersionId: 'x',
  SecretString: '{"UserName":"test","Password":"password"}',
  VersionStages: ['x'],
  CreatedDate: 'x'
}

jest.mock('aws-sdk', () => {
  return {
    config: {
      update(val) {
      },
    },
    SecretsManager: function () {
      return {
        getSecretValue: function ( { SecretId } ) {
          {
           // Adding function above to getSecretValue: is what made the original ".promise() is not a function" error go away.

            if (SecretId === 'test_creds') {
              return {
                promise: function () {
                  return mockSecretData;
                }
              };
            } else {
              throw new Error('mock error');
            }
        }
      }
    };
  }
}});

我也遇到了这个问题。也许有一种更优雅的方法来处理这个问题,它还允许更好的控制和断言,但我还没有找到。请注意,in-test选项可以更好地与较新版本的Jest配合使用

我个人通过使用手动模拟和aws sdk的自定义模拟文件解决了这个问题。在您的情况下,它看起来如下所示:

# app_root/__tests__/__mocks__/aws-sdk.js

const exampleResponse = {
  ARN: 'x',
  Name: 'test_creds',
  VersionId: 'x',
  SecretString: '{"UserName":"test","Password":"password"}',
  VersionStages: ['x'],
  CreatedDate: 'x'
};
const mockPromise = jest.fn().mockResolvedValue(exampleResponse);
const getSecretValue = jest.fn().mockReturnValue({ promise: mockPromise });
function SecretsManager() { this.getSecretValue = getSecretValue };
const AWS = { SecretsManager };

module.exports = AWS;
然后在测试文件中:

// ... imports

jest.mock('aws-sdk');

// ... your tests
因此,简而言之:

  • 不是直接在测试文件中进行模拟,而是将模拟控制权交给模拟文件,Jest知道如何在
    \uuuuumocks\uuuu
    目录中查找该文件
  • 您可以在模拟文件中为
    SecretsManager
    创建模拟构造函数
  • SecretsManager
    使用mock函数返回一个实例
    getSecretValue
  • getSecretValue
    返回模拟承诺
  • 模拟承诺返回
    示例响应

八达邦,八达邦

如果你投反对票,请留下一条评论,解释原因,以便我能理解问题所在。请你澄清是什么让新的解决方案起作用。我可以看到,在(旧版本和新版本)中,
getSecretValue()
函数返回一个带有
promise
字段的对象,那么为什么它在旧版本中失败,但在新版本中通过呢?顺便问一下,是第一次考试还是第二次考试不及格?