Ric*_*uza 0 mocking amazon-s3 node.js jestjs aws-lambda
我正在尝试使用 Jest 在本地 Node.JS AWS Lambda 函数中模拟对 putObject 的调用,但由于某种原因,我一直在期望中收到 0 次调用。
这是我的主要功能(index.js):
const S3 = require("aws-sdk/clients/s3");
const s3 = new S3();
exports.handler = async (event) => {
putFunction = async (params, callback) => {
await s3.putObject(params, callback).promise();
};
const params = {
Bucket: "some value",
Key: "some key value",
ContentType: "application/json",
Body: "some body value",
};
const callback = {
function(err, data) {
console.log(JSON.stringify(err) + " " + JSON.stringify(data));
},
};
putFunction(params, callback);
}
Run Code Online (Sandbox Code Playgroud)
我尝试将 async 添加到我的测试函数中,因为我认为这是一个异步问题,但我似乎仍然收到相同的错误。这是我的测试代码(index.test.js):
let myHandler = require("../../src/lambda/index");
const mockedPutObject = jest.fn();
jest.mock("aws-sdk/clients/s3", () => {
return class S3 {
putObject(params, cb) {
mockedPutObject(params, cb);
}
};
});
it("has to mock s3#putObject", () => {
const params = {
Bucket: "test1",
Key: "test2",
ContentType: "application/json",
Body: "test3",
};
const callback = {
function(err, data) {
console.log(JSON.stringify(err) + " " + JSON.stringify(data));
},
};
const putFunc = myHandler.handler.putFunction;
putFunc;
expect(mockedPutObject).toHaveBeenCalledWith(params, callback);
});
Run Code Online (Sandbox Code Playgroud)
任何帮助都会很棒。
对于那些不想引入任何第三方模拟库(如aws-sdk-mock )的人来说,这是一个 Jest/Node 的唯一答案。
问题(在您的答案中没有看到错误本身)很可能与.promise()您的实现代码中的 相关。
您已经在实现中添加了它,以告诉 SDK 为您调用的任何操作返回一个承诺。
await s3.putObject(params, callback).promise();
Run Code Online (Sandbox Code Playgroud)
返回的 Promise 要么拒绝错误,要么用数据解决。
这意味着在基于Promise 的方法中,您可以完全省略回调。
await s3.putObject(params).promise();
Run Code Online (Sandbox Code Playgroud)
(取自这篇 AWS 博客文章)
您可以:
.then((data) => {
// ... do stuff
})
.catch((err) => {
// ... handle error
}
Run Code Online (Sandbox Code Playgroud)
或者更好(因为看起来你已经在接受)更现代的 ES6 方法
try {
const data = await s3.putObject(params).promise()
// ... do things with data on successful response
} catch (err) {
// ... handle error
}
Run Code Online (Sandbox Code Playgroud)
您的处理程序应如下所示:
const { S3 } = require("aws-sdk");
const s3 = new S3();
exports.handler = async (event) => {
const params = {
Bucket: "some value",
Key: "some key value",
ContentType: "application/json",
Body: "some body value",
};
try {
const data = await s3.putObject(params).promise();
// ... do stuff with data
return {
statusCode: 200,
body: JSON.stringify(data),
// ... etc.
}
} catch (err) {
// ... handle error
return {
statusCode: 400, // or any 4XX, 5XX
body: '...', // whatever you wish to return on error
// ... etc.
}
}
}
Run Code Online (Sandbox Code Playgroud)
请记住,您可以省略回调,测试代码需要在处理程序.promise()的调用链中反映额外putObject的内容。
在测试文件中,SDK mock 需要配置为:a) 返回顶级S3构造函数 b) 让这个S3构造函数本身返回一个包含putObject函数的对象c) 让这个putObject本身返回一个包含promise函数的对象
这样它就可以像真正的 SDK 一样被调用:
const { S3 } = require("aws-sdk"); // require("aws-sdk") returns { S3 }
const s3 = new S3() // returns { putObject }
await s3.putObject(params) // returns { promise }
.promise(); // returns ...your_mock_response
Run Code Online (Sandbox Code Playgroud)
// You need to return the { promise } here even if you don't care about
// mock calls beyond the putObject, because the handler itself calls .promise()
// and will throw "TypeError: Cannot read property 'promise' of undefined"
const putObjectMock = jest.fn(() => ({
promise: jest.fn()
}));
jest.mock('aws-sdk', () => ({
S3: jest.fn(() => ({
putObject: putObjectMock,
})),
}));
// S3 must have jest.fn(...) over an ordinary function otherwise
// the new S3() in the handler will fail.
// Jest does its magic with the function you provide to make it callable as a constructor
const myHandler = require("../../src/lambda/index");
// Don't forget to add the "async" before the "it" callback as your handler is async
it("has to mock s3#putObject", async () => {
const params = {
Bucket: "test1",
Key: "test2",
ContentType: "application/json",
Body: "test3",
};
await handler(); // Call the handler to then assert against the mock params
expect(putObjectMock).toHaveBeenCalledWith(params);
});
Run Code Online (Sandbox Code Playgroud)
最后说明 -在模拟设置之后添加处理程序导入以防止"Cannot access 'putObject' before initialization"错误(由处理程序对 SDK 的要求引起)。
希望这可以帮助!
| 归档时间: |
|
| 查看次数: |
1020 次 |
| 最近记录: |