Lambdaテスト領域のアンケート

新井成一氏(以下、新井):ありがとうございます。ようやく全部消化できました。さっそく本日の第1回目のトピック、テスト領域の話をしたいと思います。

新井:実は投票を用意していて。ちょっとみなさん回答してもらえればと思います。

和田祐介氏(以下、和田):「ふだんやっているLambdaのテスト領域は」。

新井:上からユニットテスト、モックやSpyを使ったユニットテスト。FakeやLocalStackを使ったものです。あとはインテグレーションテスト。Lambdaの中でもいくつかレイヤーを分けているなら、これを全部とおしたテストをやっているか。インテグレーションテストに「AWS Fake」と書いてありますが、これは実際のAWS環境につなぎに行ったテスト。

LocalStackのDynamoDBではなく、クレデンシャルなどを渡して、開発環境上のDynamoDBでそのまま使おう、というものです。これはちょっと特殊だと思います。E2Eテストは、さっき話があがっていたものです。

和田:ごめんなさい。E2EテストとインテグレーションテストのAWS Fakeの違いが、ちょっとわかりませんでした。

新井:E2Eテストは、例えばAPI Gateway、Lambda、DynamoDBみたいなものを想定します。ローカルから実行して、APIリクエストを投げて正しいか。インテグレーションテストAWS Fakeは、ローカルでLambdaを起動します、接続しに行く先がLocalStackのDynamoDBではなく、AWS上のDynamoDB。ローカルで完結しないでネットワークを含めたテストです。

和田:なるほど。わかりました。

Lambdaテスト領域のアンケート結果

新井:これもあるのかなと思って。では投票をそろそろ終了します。けっこう40パーセントと少ない……。

佐藤:Lambdaを使っていた人が。

和田:そんなに多くないかもしれません。

新井:なるほど。ではそろそろ閉じます。驚きの結果を。こんな結果になりましたが、これ見てみなさんどうですか? 和田さんとか。

和田:僕が回答したのかというぐらい、僕は同じ結果ですね。

新井:和田さんはふだんどこを書いていますか?

和田:このバーとまったく一緒ですが、ユニットテスト+実際の環境のAPIを叩いて確認するテストです。AWSの、特にサーバーレスにおいては実際の環境でテストして得られる結果があまりにも大きくて。IAMしかり、さっきのSQSのダウンストリームも含め、いろいろなコンポーネントがつながっている状況だとは思いますが、そこに対してテストするところが、結果として一番得られる効果として大きいのは感じているので、今この2つという感じでやっています。

新井:他の2人、加藤さんどうですか?

加藤諒氏(以下、加藤):私も和田さんと基本同じですが、DynamoDBまわりのFakeを使ったテストを、若干厚くしたがるタイプです。ただ、インテグレーションテストをやるとき、面倒くさい部分のテストはやらないと割り切っていて。一番外側の認証の部分はやらないで、内側から。例えば、このAPI Gatewayでいうと、Lambdaのハンドラの部分からインテグ(インテグレーション)を走らせるように書いたりします。

新井:HTTPリクエストを送って、みたいな感じではないですか。

加藤:それをローカルでやろうとするとメチャクチャ面倒くさいし、それをやろうとすると、要は認証のトークンを取りに行かなきゃいけないとなる。API Gatewayだとしたら、そのAPI Gatewayをローカルでモックすることは不可能に近いと思っていて。「そこの認証トークン取れないじゃん」となるので。

「取れないじゃん」というのは、認証系が外部のAuth0を使っていることが多く、そのときに通信を投げてしまうと、さっきの定義でいくと、インテグレーションテストの範囲を外れるのでやらないという感じです。

新井:なるほど。インターネットを使ってアクセスしにいくところはしないということですね。佐藤さんはどうですか?

佐藤智樹氏(以下、佐藤):そうですね。前に和田さんが発表されていたのを見て、自分もこのバーは基本的に強くやる意識がやはりあって、ずっとやっています。手動でやる前提ですが、E2Eテストがだんだん多くなってくると時間がかかるので。インテグレーションテストのFakeなどを試してみようかなと思って、自分は少しずつ取り入れているところです。

和田:その考え方はメチャクチャいいと思います。E2Eテストで得られるものも大きいですが、さっき話したとおり、いろいろなコンポーネントが連なっているので、エラーで「テストNGでした」となったときに、どこがダメだったのかがわかりません(笑)。けっこう時間がかかります。

だから、ちょっと範囲を狭めるという意味でも、インテグレーションテストをやるのは、僕はありだと思っています。

佐藤:そうですね。何度も言ってしまっていますが、ちょっとDBまわりで失敗が多くて。そのあたりは、もうローカルでどういうのをパラメータとして入れたらいけるのかを確認できたほうが、あとで楽なので。

和田:それはそうですね。

加藤:私はけっこうFakeは厳選するようにしています。なんでもかんでも他のマイクロサービスやS3、DynamoDBを全部Fakeするのはむしろよくないと思っていて、本当にやりたいところだけ。

DynamoDBはやらないといけないからやるけけど、結局なんでもかんでもやっていくと、マイクロサービスで開発しているのに、他のマイクロサービスに全部Fake作ることに行き着いてしまって、元のDockerファイルがえげつないことになってしまうので。本当にやりたいところに絞ってやるのがいいかなと、個人的には思っています。

佐藤:すごくわかります。SSMはE2Eでもわかるから、別にいいかなと思っていますが、自分もSSMからクレデンシャルを持ってきて、DBに接続みたいなことをテストでやっています。DBのところだけ、Fakeをローカルでちょっと試すようなことはやっています。

新井:なるほど。やはりこのあたりのバランスは大事ですね。コストに対してメリットがあるか。

佐藤:そうですね。

パターン化できるテストは飛ばすのもあり?

和田:ちょっとテストの趣旨から外れてしまいますが、さっき話したDynamoDBの部分の確認は確かにやりにくいところがあると思いますが、わりとDynamoDBとS3に対して指定するパラメータは、けっこうパターン化してきませんか? CRUD処理などでcreateするときはPutItemやUpdateItemを使うし、取ってくるときはDynamoDBから取ってきて、デシリアライズというか、オブジェクトに変換するようなことをやると思いますが。

そのあたりがいろいろパターン化できると、わりとテストで確認しなければいけないところもちょっとずつ減らしていけるのかもしれない、というところが僕の中にあって(笑)。ちょっとテストの趣旨から外れますが、うまくパターンにはめて、「これは動いた実績があるから、E2Eは飛ばしてテストでいいか」というのも1つ考え方としてはあるかもしれません。

加藤:わかります。マルチテーブル戦略でやっているのなら、ぜんぜんそれでいけると思っていて。わりと私がシングルテーブル戦略厨なので。ただ、書き込むときにわりとDynamoDBトランザクションをバリバリ使ったり、条件付き書き込みとかをし過ぎちゃうと、Fakeがないとつらい。

和田:それはそうですね。

加藤:CRUDだと、お話されたとおり書けますね。

和田:でもDynamoDBのメッセージとして、現実世界のユースケースと密結合の設計にしろというDynamoDB設計ドキュメントからのメッセージがあるので、Fakeを使ってテストするのは本当にやったほうがいいと思います。僕が今話したのは、あくまでパターン化できるときには飛ばせる選択肢もある。

加藤:そうですね。

テスタブルなソフトウェア設計のアンケート

ちょっといろいろ用意してきましたが、先にアンケートを取っちゃいます。「テスタブルなソフトウェア設計」、これをみなさん1分で投票してください。かなり偏った選択肢ですが(笑)。

和田:でもこれ、ユニットテストとPytestのどちらを使っているのか、メチャクチャ気になります。社内でもけっこうこのあたり割れるんですよね。

加藤:Pytestが多い気はしますが。

新井:あとは、その他がどれくらいあるのかは若干気になります。

佐藤:さっき紹介してくれたものがあまり知らなかったですしね。外部の発表とかを聞いていると、サーバーレスフレームワークでいろいろ出ているようですが、あまりキャッチアップできていなくて。ぜひよかったら書いてもらえると。

新井:はい。いったん投票終了します。結果の共有、ドドン!

加藤:やはりPytestか。

新井:Pythonがもともと多いですからね。次点でJESTです。LocalStackもMotoも、まぁまぁ使っているという感じ。

もう1個だけアンケートを取らせてください。今日できればソフトウェア設計の話もしたかったんですけど、あまりできてなくて(笑)。

ここにいるメンバーはクリーンアーキテクチャはけっこう推している派なのかなと思っていて、そういう話もできたらよかったな。みなさんはどれぐらい意識してソフトウェア設計をしているか、ちょっと気になったので。

和田:Functionとしての側面を重視する観点で、あまりコテコテにしてないです。クリーンアーキテクチャに完全に準拠しているというよりかは、先ほど佐藤さんが話していましたが、今のところはざっくりレイヤーを分けるぐらいな感じです。

佐藤:クリーンアーキテクチャに寄せると、コントローラがハンドラにあたるのかなと思って。そうなると、ハンドラからユースケースは微妙かな。

和田:厳密には変ですね。

APIリクエストのボディのバリデーションテスト

加藤:今このアンケートを取っている最中に、きている質問に1つ答えますか。「APIリクエストのボディのバリデーションをテストするときに、実行速いのでテストは単体テストでたくさん書いていますが、デプロイされるE2Eで、少ないパターンでやっています。みなさんはどうしていますか?」。私はAPI GatewayとLambdaを使うときにプロキシ統合を使うことが多いので、その場合の話をすると、バリデーションは私もユニットテストでいっぱい書きます。

E2Eで質問された方と同じですが、そんなにがっつりバリデーションを書いたりはしません。テストにリクエストを投げたりはしないです。和田さんと佐藤さんで、プロキシ統合をやる派の人がいたら、その場合の回答を聞いてみたいです。

和田:ごめんなさい。プロキシ統合ではありませんが、E2Eテストのパターンという意味だと基本的には同じで。あとは、APIになるとレスポンスステータスあたりは確認したほうがいいかなというのはあるので、E2Eテストの場合も400になることとか、404になることは、テストをE2Eテストの中に含めるようにはしています。

ただ、その中のバリデーションをいっぱいやるのではなくて、そこの部分はユニットテストに任せるのは同じです。佐藤さんはどうですか?

佐藤:自分も同じような感じです。というのは、E2Eが増えすぎるとテストパターンがアイスクリームの図が出てきて、「E2Eが多くなるとあまりよろしくないよね」というのを、けっこう見ると思います。あれと同じで、E2Eでバリデーションをやりまくるよりは、テストをできるだけ厚くして、E2Eはできるだけ少なめに。効果的に使えればいいと思ってやっています。

新井:ありがとうございます。件だけ、QA先ほどの投票の結果を一応共有しています。ソフトウェア設計意識しているかという話ですが、「あまり意識していない」が一番多かったかなと思います。

すごく中途半端ですが(笑)。締めに入ります。今回の話ですが、佐藤智樹さんが書いてきてくれたブログにけっこうまとまっているので、興味ある方は見てもらえればと思います。

最後すごく駆け足になってしまいましたが、本日はウェビナー参加ありがとうございました。以上をもって終わりにします。