use*_*776 2 class jestjs aws-sdk
我正在尝试用玩笑来模拟 aws-sdk。其实我只关心一个功能。我怎样才能做到这一点?我已经阅读了有关用笑话模拟类的文档,但文档很复杂,我不太理解它们。
这是我最好的尝试:
处理程序.test.js
'use strict';
const aws = require('aws-sdk');
const { handler } = require('../../src/rotateSecret/index');
jest.mock('aws-sdk');
const event = {
SecretId: 'test',
ClientRequestToken: 'ccc',
Step: 'createSecret',
};
describe('rotateSecret', () => {
it.only('should not get or put a secret', async () => {
aws.SecretsManager.mockImplementation(() => ({
getSecretValue: () => ({}),
}));
expect.assertions(1);
await handler(event);
// You can see what I am trying to do here but it doesn't work
expect(aws.SecretsManager.getSecretManager).not.toHaveBeenCalled();
});
});
Run Code Online (Sandbox Code Playgroud)
处理程序.js
exports.handler = async (event) => {
const secretsManager = new aws.SecretsManager();
const secret = await secretsManager.describeSecret({ SecretId: event.SecretId }).promise();
if (someCondition) {
console.log("All conditions not met");
return;
}
return secretsManager.getSecretValue(someParams)
};
Run Code Online (Sandbox Code Playgroud)
好的,我的处理方法如下:
创建一个实际的模拟aws-sdk并将其放入__mocks__/aws-sdk.js项目根目录的文件中
// __mocks__/aws-sdk.js
class AWS {
static SecretsManager = class {
describeSecret = jest.fn(() =>{
return { promise: ()=> Promise.resolve({ ARN: "custom-arn1", Name: "describeSec" })}
});
getSecretValue = jest.fn(() =>{
return {promise: ()=> Promise.resolve({ ARN: "custom-arn2", Name: "getSecretVal" })
});
};
}
module.exports = AWS;
Run Code Online (Sandbox Code Playgroud)
我以前使用过 static SecretsManager,因为AWS类从未实例化,但它想要访问SecretsManager类。
在里面SecretsManager,我定义了 2 个函数并使用jest.fn.
现在与您在测试文件中所做的内容相同:
jest.mock('aws-sdk');
Run Code Online (Sandbox Code Playgroud)
要测试您的模拟函数是否被调用,这是棘手的部分(所以我将在本文末尾详细介绍这一点)。
更好的方法是在所有处理完成后对主函数的最终结果进行断言。
回到您的测试文件,我只需使用await(正如您已经拥有的那样)调用处理程序,然后对最终结果进行断言,如下所示:
jest.mock('aws-sdk');
Run Code Online (Sandbox Code Playgroud)
为此,您需要调整主文件本身,并且需要从主函数体中handler.js取出,如下所示:invocation of secrets Manager
// test.js
describe("rotateSecret", () => {
it.only("should not get or put a secret", async () => {
const event = {name:"event"};
const result = await handler(event);
expect(result).toEqual("whatever-your-function-is-expected-to-return");
});
});
Run Code Online (Sandbox Code Playgroud)
然后回到文件中,在启动处理程序函数之前,test.js您需要类似地声明调用,如下所示:SecretsManager
const secretsManager = new aws.SecretsManager(); // <---- Declare it in outer scope
exports.handler = async (event) => {
const secret = await secretsManager
.describeSecret({ SecretId: event.SecretId })
.promise();
if (someCondition) {
console.log("All conditions not met");
return;
}
return secretsManager.getSecretValue(someParams);
};
Run Code Online (Sandbox Code Playgroud)
这将允许您对函数调用以及传递的参数进行断言。
我在函数作用域之外声明它的原因是告诉 Jest 它
secretsManager应该存在于全局作用域中的某个位置,并且应该从那里使用它。
以前,我们在函数作用域内声明了它,因此 Jest 会调用它,但我们无法访问它。
我们不能像这样直接引用它,AWS.SecretsManager.getSecretManager因为getSecretManager方法仅在实例化该类后才可用SecretsManager(即使您这样做,您也会获得该类的一个新实例,这对任何断言都没有帮助)。
明显的问题是 - 你在每次调用时都对函数进行存根处理,也许你不希望这样。
也许您只想针对特定测试将其存根一次,但对于其余测试,您希望它正常运行。
在这种情况下,您不应创建__mocks__文件夹。
相反,创建一个一次性的假文件,但确保您的SecretsManager调用像以前一样位于测试文件的外部范围内。
//test.js
describe("rotateSecret", () => {
const secretsManager = new aws.SecretsManager(); // <---- Declare it in outer scope
it.only("should not get or put a secret", async () => {
const event = {name:"event"};
await handler(event);
// Now you can make assertions on function invocations
expect(secretsManager.describeSecret).toHaveBeenCalled();
// OR check if passed args were correct
expect(secretsManager.describeSecret).toHaveBeenCalledWith({
SecretId: event.SecretId,
});
});
});
Run Code Online (Sandbox Code Playgroud)