実務でLambdaのコードの単体テストをしていて、aws-sdk-mockを使ってDynamoDBへのアクセスをモック化しようとしてもモック化されず困ったのですが、先輩に解決していただいたので、詰まった原因をシェアします。
テスト環境
- MacOS 11.6.2
- NodeJS v16
- jest v27.4
ソースコード
以下の記事を参考にして書きました。
コード
put.js
const AWS = require('aws-sdk');
const docClient = new AWS.DynamoDB.DocumentClient();
AWS.config.update({"region": "ap-northeast-1"});
exports.handler = async (event) => {
return await Promise.all(event.Records.map(async (record) => {
var data = JSON.parse(record.body);
var params = {
TableName: "member-table",
Item: {
country: data.country,
id: Number(data.id),
Name: data.name
}
};
console.log(JSON.stringify(params, null, 2));
return await docClient.put(params).promise()
.then(() => {
const response = {
statusCode: 200,
body: params.Item
};
console.log(response);
return response;
})
.catch((err) => {
const response = {
statusCode: 500,
body: "NG"
};
console.error(response);
return response;
});
}));
};
テストコード
put.test.js
const event = require("./event_data");
const put = require("./put");
const aws = require("aws-sdk");
const awsMock = require("aws-sdk-mock");
var dbTable = [];
var putCalledCount = 0;
const replacePut = (params) => {
putCalledCount++;
(プライマリキーが重複する場合dbTableからデータを削除)
dbTable.push(params.Item);
return params.Item;
};
awsMock.setSDKInstance(aws);
awsMock.mock("DynamoDB.DocumentClient", "put", replacePut);
// putのモック関数(replacePut)が呼ばれることをテスト
describe("put-data-test", () => {
test("putItem function called", async () => {
const response = await put.handler(event);
expect(putCalledCount).toBe(1);
awsMock.restore("DynamoDB.DocumentClient");
});
});
テストデータ
event_data.json
{
"Records": [
{
"messageId": "19dd0b57-b21e-4ac1-bd88-01bbb068cb78",
"receiptHandle": "MessageReceiptHandle",
"body": "{\"country\": \"Japan\",\"id\": \"1\",\"Name\": \"Taro\"}",
"attributes": {
"ApproximateReceiveCount": "1",
"SentTimestamp": "1523232000000",
"SenderId": "123456789012",
"ApproximateFirstReceiveTimestamp": "1523232000001"
},
"messageAttributes": {},
"md5OfBody": "{{{md5_of_body}}}",
"eventSource": "aws:sqs",
"eventSourceARN": "arn:aws:sqs:us-east-1:123456789012:MyQueue",
"awsRegion": "us-east-1"
}
]
}
これでjestを実行してみると、putCalledCount=0のままでテスト失敗するんですよね。。
put操作がモック化されずそのままDynamoDBにアクセスされます。
この原因が分からず悩んでいたところ先輩に解決していただきました。
原因
原因は、モジュールのrequireとモック化の順番が逆だったそうです。
const put = require("./put");
...
awsMock.setSDKInstance(aws);
awsMock.mock("DynamoDB.DocumentClient", "put", replacePut);
となっていたことです。
これを、
awsMock.setSDKInstance(aws);
awsMock.mock("DynamoDB.DocumentClient", "put", replacePut);
const put = require("./put");
としてやるとうまくいきました。
モック化したインスタンスを作成してからrequireしないとモック化された操作がインポートされないんですね。
そしてこれはaws-sdk-mockに限らず、一般的なjestのモック化操作においても同じです。
aws-sdkのモック化以前にjestのモック化の理解が足りなかったみたいです。。