为 JavaScript 开玩笑的单元测试模拟 Secrets Manager 模块
Mocking Secrets Manager module for JavaScript jest unit tests
我在为开玩笑的单元测试模拟 AWS Secrets Manager 模块时遇到问题...它出错的部分是 .promise()。当我删除它时,代码对真正的 Secrets Manager 不起作用,所以我认为它需要留在那里。我如何模拟 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
非常感谢任何建议或指示!
谢谢你看我的 post.
我终于让它工作了...估计它会在 post 提出问题后不久发生,但我不会删除 post 我将分享我如何将模拟更改为让它发挥作用,以防它能帮助其他人。
注意:这只是更新的模拟,测试与上面的问题相同。
// 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 知道在
__mocks__
目录中查找该文件。
- 您在 mock 文件
中为 SecretsManager
创建一个 mock 构造函数
SecretsManager
returns 具有模拟函数的实例 getSecretValue
getSecretValue
returns 模拟承诺
- 模拟承诺 returns
exampleResponse
巴达繁荣,巴达 bing。 You can read more here.
我在为开玩笑的单元测试模拟 AWS Secrets Manager 模块时遇到问题...它出错的部分是 .promise()。当我删除它时,代码对真正的 Secrets Manager 不起作用,所以我认为它需要留在那里。我如何模拟 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
非常感谢任何建议或指示!
谢谢你看我的 post.
我终于让它工作了...估计它会在 post 提出问题后不久发生,但我不会删除 post 我将分享我如何将模拟更改为让它发挥作用,以防它能帮助其他人。
注意:这只是更新的模拟,测试与上面的问题相同。
// 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 知道在
__mocks__
目录中查找该文件。 - 您在 mock 文件 中为
SecretsManager
returns 具有模拟函数的实例getSecretValue
getSecretValue
returns 模拟承诺- 模拟承诺 returns
exampleResponse
SecretsManager
创建一个 mock 构造函数
巴达繁荣,巴达 bing。 You can read more here.