[小ネタ]TypeScript+JestでローカルからLambdaを実行しテストする

Lambdaをローカルから実行してレスポンスのテストを行います。CloudWatch Eventsでインターバル実行するLambdaなどのAPI Gateway経由で実行できないLambdaをテストする場合参考にしてください。
2020.06.23

はじめに

CX事業本部@東京の佐藤智樹です。

今回はLambdaをローカルから実行してレスポンスのテストを行います。

API GatewayなどからLambdaをキックする場合やDynamoDBなどに書き込む場合は、E2Eテストを比較的簡単に書くことができます。ただDBへのアウトプットがない場合やCloudWatch Eventsからインターバル実行する場合などは少しテストが書きづらいです。そこでローカルからLambdaを実行してテストする方法を紹介します。

ユニットテストで確認しきれない内容のテストができるので、APIリクエストでテストできない場合などで参考にしてください。

前提条件

本記事ではLambdaのデプロイに関する情報などは省略します。TypeScriptを使用したデプロイ方法を知らない場合は以下の記事や公式のドキュメントなどを参考にしてください。

また今回は同期的実行で戻り値を設定する場合のLambdaを対象にテストを書きます。非同期実行するLambdaの場合は戻り値が無いので別の手段を考えるか、余分な戻り値の実装を足すことになるので検討の上実施してください。

Lambdaの準備

まずテストするためのLambdaを準備します。以下のソースを準備してトランスパイル後デプロイしてください。 コード自体は受けたデータの一部を返却する単純なLambdaです。JavaScriptで同じ出力になるコードを書いてデプロイしても問題ありません。

index.ts

export interface TestEvent {
  id: number;
  eventValue?: string;
}

export interface ReturnEvent {
  returnValue: string;
}

export async function handler(event: TestEvent): Promise<ReturnEvent | void> {
  console.log(JSON.stringify(event));
  if (event.eventValue) return { returnValue: event.eventValue };
}

テストコードの準備

次に上記のコードをローカルからテストするためのコードを記載します。AWS SDKを使用して、ローカルからLambdaを同期的に実行して返却値をテストします。テストにはJestを使用します。

import * as AWS from 'aws-sdk';

AWS.config.update({
  region: 'ap-northeast-1',
});

const lambda = new AWS.Lambda();

describe('Lambda単体のテスト', (): void => {
  test('正常なイベントがリクエストされた場合', async (): Promise<void> => {
    const testEvent = { id: 0, eventValue: '10' };
    const returnEvent = { returnValue: testEvent.eventValue };

    const result = await lambda
      .invoke({
        FunctionName: `handler-test`,
        InvocationType: 'RequestResponse',
        Payload: JSON.stringify(testEvent),
      })
      .promise();

    if (result.Payload) {
      const payload = JSON.parse(result.Payload.toString());

      expect(payload).toHaveProperty('returnValue');
      expect(payload).toEqual(returnEvent);
    }
  });
});

上記のテストコードを作成後、aws-cliを使える状態にしてローカルからテストを実行します。以下は実行時の出力結果です。Lambdaを実行して戻り値のテストが可能になりました。

$ yarn test tests/handler.test.ts

PASS  tests/handler.test.ts
  Lambda単体のテスト
    ✓ 正常なイベントがリクエストされた場合 (194ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.994s, estimated 5s

念のためにCloudWatch Logsを確認すると正常に実行されていることが確認できます。