[AWS.4] Lambda関数のテスト

# 1. 概要
API Gateway に対応した Lambda関数をテストするには、API Gateway の管理画面から対象APIを選んで「テスト」画面を開き、テスト用の入力パラメータを指定して当該関数を呼び出す必要があります。
また、VisualStudio のテストプロジェクトから Lambda関数を呼び出して動作をテストすることも可能です。

本記事では、次の二つのテスト方法について記述します。
1. API Gateway の API 呼び出しテスト
1. VisualStudio テストプロジェクトからの呼び出しテスト

# 2. API Gateway の API 呼び出しテスト
API Gateway管理画面から、作成した API（EchoSample-API）を選択します。
その後、ツリー項目の「ANY」をクリックすると、リクエスト〜レスポンス の流れを示すフロー図が表示されます。
![スクリーンショット 2022-08-03 22.08.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/5b5ab9e5-79d8-6c6f-19b6-a6c71493fb59.png)
図中、「クライアント」上部の「テスト」リンクをクリックすると、フローの流れで Lambda関数を呼び出すための メソッドテスト画面が表示されます。
REST API では複数のメソッド種別（GET/POST/PUT/DELETE など）を実装しますが、それら全てについて呼び出しテストを実行することが可能です。

以下、GET/POST メソッドの呼び出しテストの例となります。

### GET メソッドテスト
メソッド プルダウンリストで「GET」を選択し、「クエリ文字列」には「Param1=Value1」と入力します。
この「Param1」は [AWS.3] で改造したLambda関数の中で パラメータ名 として使用しており、ここでの入力値「Value1」をプログラム内から取得しています。
![スクリーンショット 2022-08-03 22.20.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/29b209ff-846c-c4ba-1844-8dc82e0004e2.png)
画面下部の [テスト]ボタンをクリックすると、実行結果（Lambda関数からの返却値）が表示されます。
![スクリーンショット 2022-08-03 22.22.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/da0febef-ac08-9ef7-69c1-e896254cfcee.png)
実行時のログも表示されるので、どのようなパラメータを Lambda関数へ渡しているのかなどを確認することも可能です。（詳細説明は割愛します）

### POST メソッドテスト
メソッド プルダウンリストで「POST」を選択し、「クエリ文字列」欄は空欄にします。
「リクエスト本文」には「Value1」とだけ入力しておきます。
![スクリーンショット 2022-08-03 22.29.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/fe83e7e7-8c4d-bec7-b773-69871b701dc0.png)
![スクリーンショット 2022-08-03 22.29.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/314506e9-85a6-1f0e-1b92-32f196559d28.png)
画面下部の [テスト]ボタンをクリックすると、実行結果（Lambda関数からの返却値）が表示されます。
![スクリーンショット 2022-08-03 22.30.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/2c63c063-e6b5-10e2-5b75-8da196a56961.png)

:::note info
本来、REST API の本文は標準化されたフォーマット（XMLやJSON）のデータを格納しますが、[AWS.3]で改造したサンプルに同フォーマットを認識する処理はありません。
そのため、ここでは単純な文字列「Value1」のみを本文としています。
（あくまでサンプルということで）
:::


# 3. VisualStudio テストプロジェクトからの呼び出しテスト
```dotnet new lambda.EmptyFunction```コマンドでプロジェクトを作成した際、testフォルダの下に「EchoSample.Tests」というテストプロジェクトが作成されています。
<img width="70%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/7feceede-982a-a5e9-2280-bbf42d236f2b.png" />
このプロジェクトを Visual Studio のソリューションへ追加すると、作成したテストメソッドから Lambda関数を呼び出せるようになります。
また、テストメソッドをデバッグ実行すると Lambda関数の中へステップインできるので、関数自体をデバッグする際にも利用可能です。

### VisualStudio ソリューションへの追加
ソリューションへの [追加]-[既存のプロジェクト]　で、作成された「test/EchoSample.Tests」フォルダ下のプロジェクトファイル（拡張子「.csproj」）を指定してください。
このサンプルでは、「EchoSample.Tests.csproj」を指定します。

無事に取り込まれたプロジェクトを展開すると、テストに必要な「NuGet」パッケージなどは既に登録されている状態です。
<img width="60%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/29093cab-b18d-2ce2-461a-092d3fd36ba8.png" />

### テストメソッドの改造
プロジェクト作成時に自動生成された FunctionTest.cs には、Lambda関数を呼び出す簡単なテストメソッドが記述されています。
Lambda関数は [AWS.3] で大きく改造してしまったため、テストメソッドもそれに合わせて修正します。

#### (1) 修正前のテストメソッド
プロジェクトテンプレートに基づいて自動作成されたLambda関数は、「第１引数で受け取った文字列を大文字に変換して返却する」という仕様でした。
テストメソッドも「返却値が大文字に変換されていれば成功」という仕様で作成されています。

```C#
using Xunit;
using Amazon.Lambda.Core;
using Amazon.Lambda.TestUtilities;

namespace EchoSample.Tests;

public class FunctionTest
{
    [Fact]
    public void TestToUpperFunction()
    {
        // Invoke the lambda function and confirm the string was upper cased.
        var function = new Function();
        var context = new TestLambdaContext();
        var upperCase = function.FunctionHandler("hello world", context);

        Assert.Equal("HELLO WORLD", upperCase);
    }
}
```

#### (2) 修正後のテストメソッド
下記が修正後のテストメソッドです。
原型を留めているのは最初の２行のみで、ほとんどを新たに作り直しています。
（メソッド名も変更しています）

```C#
public class FunctionTest
{
    [Fact]
    public void TestEchoValueFunction()
    {
        var function = new Function();
        var context = new TestLambdaContext();
        var request = new APIGatewayProxyRequest();

        // エコー文字列をリクエスト本文にセット。
        string echoValue = "Value1";
        request.Body = echoValue;

        // Lambda関数の呼び出し
        APIGatewayProxyResponse response = function.FunctionHandler(request, context);

        // 返却ステータスが「OK(200)」ならば成功。
        Assert.Equal((int)HttpStatusCode.OK, response.StatusCode);

        // レスポンス本文の内容を " echo: " という文字列の前後に分割。
        string pattern = " echo: ";
        string body = response.Body;
        string[] token = Regex.Split(body, pattern);

        // 分割結果（文字列配列）が存在する場合は成功。
        Assert.NotEmpty(token);

        // 文結結果（文字列配列）の要素数が「２個」ならば成功。
        Assert.Equal(2, token.Length);

        // 分割した後半部分がリクエスト本文にセットした値と一致したら成功。
        Assert.Equal(echoValue, token[1]);
    }
}
```

修正後のテストメソッドでは、Lambda関数を呼び出す際の第１引数と返却値の「データ型」を変更しています。
　第１引数：　APIGatewayProxyRequest
　返却値　：　APIGatewayProxyResponse

「APIGatewayProxyRequest」には Lambda関数へ渡すテストデータを格納します。
このサンプルでは省略していますが、他のリクエストパラメータも設定可能です。
（例. ```request.HttpMethod = "GET";```）

返却値（APIGatewayProxyResponse型）には Lambda関数が返却した内容が格納されており、確認する必要のある各プロパティ値を取り出して成否を判定します。
判定には Assert クラスメソッドを使用しますが、一般的なテストコードと変わらないので利用方法は割愛します。

### テストの実施
Visual Studio にて [表示]-[テスト] を選択してテストツリー画面を開きます。
テストメソッドの上でポップアップメニューを開き、[テストを実行する] または [テストのデバッグ] をクリックすると、そのテストメソッドが実行されます。
<img width="60%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90456/308b3e68-d935-8972-5b6b-d1bcc3f7e05c.png" />

# 4. 終わりに
本記事では、次の二つのテスト方法について記述しましたが、製造段階でのデバッグやテストは Visual Studio のテストプロジェクト を利用するケースが多くなると思われます。
1. API Gateway の API 呼び出しテスト
1. VisualStudio テストプロジェクトからの呼び出しテスト

ただし、テストプロジェクトはあくまでローカルPC上での実行環境であり、<font color="red">AWS 上の実際の実行環境とは異なる</font>という点には十分に注意してください。
AWS が提供する各種リソースや環境に依存する処理を Lambda関数へ組み込んだ場合、ローカルPC 環境では正常に動作しない場合があります。

次回は、Lambda関数から AWS サービスを呼び出すサンプルを作成してみます。

:::note info
インターネットを介してアクセス可能な AWS サービスについては、ローカルPC上のテストプロジェクトから呼び出した Lambda関数内からも利用可能と考えられます。
:::

:::note warn
AWS へデプロイした Lambda関数をリモートから直接デバッグ実行できれば環境差異に留意する必要はなくなるかもしれませんが、その間は**常に通信し続けている**ことに気を付けねばなりません。
通常の通信費 だけではなく AWS の利用料金も急上昇する恐れがあるため、終日リモートでデバッグする際は費用面の検討・対策も必要となるでしょう。
:::