テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト

24K Views

July 18, 22

スライド概要

みなさん自動テストしてますか?AWSサーバレスアプリケーション開発において、テストピラミッドの考え方を参考にしながら「続けられるテスト基盤」を作っていきましょう。特にサーバレスに限らない話になったような気もしますがよろしくお願いします。

profile-image

広島市のプログラマ

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

テストピラミッドで考える、継続するAWSサーバレスア プリケーション自動テスト CX事業本部デリバリー部 @dyoshikawa 2022/7/26(作成 2022/7/18) 1

2.

自己紹介 自己紹介 クラスメソッド株式会社 CX事業本部デリバリー部LINEグループ https://dev.classmethod.jp/author/dyoshikawa 最近はzennでブログ書いてます テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 2

3.

自己紹介 京都市出身 法学部卒 プログラマになって(たぶん)4〜5年くらい 広島市在住 ふるさと勤務 テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 3

4.

導入 導入 みなさん、自動テストしてますか? 発表者は自動テストが大好きです サーバレス案件で自動テストおじさんムーブをしている テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 4

5.

導入 ところで 知り合いのエンジニアと飲んでいて「Lambdaを使ったサーバレスAPIはテストしづらい 感じがする」という意見を聞くことがあった フロントエンドのテストが薄い案件をちらほら見る気がする => バックエンド・フロントエンド・そしてサーバレスアプリケーション全体に自動テストを 被せる戦略を考えてきたので共有する => 自動テストは構築だけでなく継続が大きな課題になる => 「続けられる」自動テストのためにテストピラミッドの考え方を導入する テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 5

6.

なぜ「自動」テストしたいのか? なぜ「自動」テストしたいのか? 手動テストオンリーの品質担保は茨の道 原則、リリース毎にソフトウェアすべてを手動テストしなければならない しかも手動テストの工数は増え続ける フェーズ1テスト、フェーズ2テスト(フェーズ1含む)、フェーズ3テスト(フェー ズ1・フェーズ2含む)…… テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 6

7.

なぜ「自動」テストしたいのか? すべて手動(人力)テストでカバーする場合 フェーズ毎の必要人員の増加が激しくなりやすい フェーズ1+2+3範囲をテスト フェーズ3開発 フェーズ1範囲をテスト フェーズ1開発 フェーズ1+2範囲をテスト フェーズ2開発 テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 7

8.

なぜ「自動」テストしたいのか? リリースが重なるごとに必要な人員は増加し、開発速度は低下していく 変更に必要なコストが非常に重くなり、ランタイム、ライブラリ、周辺ツール類のアッ プグレードが敬遠されがちになる 既知の脆弱性の放置 新機能が使えないことによる生産性への影響 追加で導入したいライブラリやツールと依存関係がある場合、バージョンが古いこ とが障壁になることも => そこで「自動」テスト テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 8

9.

なぜ「自動」テストしたいのか? 自動テストの恩恵 品質の観点 オンボーディングの観点 変更可能性の観点 テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 9

10.

なぜ「自動」テストしたいのか? 品質の観点 数秒〜十数分以内ですべてのテストをやり直すことができる (手動テストと比較して)オペミスを防ぐことができる テストケースを厚くする判断がしやすい 品質を積み上げることができる テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 10

11.

なぜ「自動」テストしたいのか? オンボーディングの観点 テストコードが仕様書になる 関数やクラスの期待値がわかりやすい チームメンバーに対して「自動テストがPassしたら影響についてはOKです」という依頼 の仕方が可能になる => 開発チームがスケーラブルになる テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 11

12.

なぜ「自動」テストしたいのか? 変更可能性の観点 「ソフト」ウェアなので変更可能であることをキープし続けなければならない 『Clean Architecture』の受け売り なぜ? 機能追加・仕様変更に耐える必要があるから 開発速度を落とさないため ランタイム・ライブラリ・周辺ツールをアップデートし続けなければならない 特に脆弱性対応の観点 テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 12

13.

なぜ「自動」テストしたいのか? 自動テスト基盤を積み上げられた場合 フェーズ毎の必要人員の増加は緩やかになる(はず) テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 13

14.

なぜ「自動」テストしたいのか? 仮説に基づいたチャート: 自動テスト基盤を構築することで工数の爆発を抑える! テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 14

15.

自動テストに費やすコスト・メンテナンスが辛い? 自動テストに費やすコスト・メンテナンスが辛い? 効率化・合理化のため自動テスト基盤であるはずが、逆に現場を苦しめてしまう懸念も無視 できない テストを書くのに時間がかかる テストを実行するのに時間がかかる たまに失敗するテストがある 仕様変更でテストが壊れる => 自動テストのメンテナンス工数が爆発してしまう問題 テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 15

16.

自動テストに費やすコスト・メンテナンスが辛い? どうしたら? 安定・高速なテストを厚くし、不安定・低速なテストを薄くする => テストピラミッド テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 16

17.

テストピラミッドで考える テストピラミッドで考える 『初めての自動テスト』Jonathan Rasmusson、玉川 紘子、オライリージャパン 「1章 テストのピラミッド」 新しいテストを追加するときには、まずユニットテストで対応できないかどうかを確認 する。 テストは、常にピラミッドのなるべく下の層に入れるようにする。 テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 17

18.

テストピラミッドで考える 不安定 低速 ⾼コスト UI 統合 ユニット 安定 ⾼速 低コスト この形に近づけると「続けられる」自動テスト基盤になる! テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 18

19.

テストピラミッドで考える UI?統合?ユニット? 『初めての自動テスト』内では明確な定義が言及されています ただ、実際の案件ではブレがち 今回はGoogleのTest Sizesを参考に基準を考える Size 定義 Small DBを使わない/ネットワークアクセスが発生しない/ファイル操作がない Medium DBを使用する/ネットワークアクセスはlocalhostのみ/ファイル操作がある DB を使用する / ネットワークアクセスがある / ファイル操作がある / 外部システム Large 連携がある テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 19

20.

テストピラミッドで考える SML基準のテストピラミッド 不安定 低速 ⾼コスト Large Medium Small 安定 ⾼速 低コスト テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 20

21.

AWSサーバレスアプリケーションにおける実践 AWSサーバレスアプリケーションにおける実践 アプリケーション仕様(仮定) Web会員証アプリケーション 会員登録 会員情報表示 QRコード表示 ポイント蓄積・消費 前提: ロジックは比較的バックエンドに寄っている テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 21

22.

AWSサーバレスアプリケーションにおける実践 技術スタック(仮定) Frontend: React (TypeScript) CloudFront + S3 Backend: Node.js (TypeScript) APIGateway + Lambda + DynamoDB Infrastructure as Code: AWS CDK テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 22

23.

AWSサーバレスアプリケーションにおける実践 テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 23

24.

バックエンドのテスト バックエンドのテスト テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 24

25.

バックエンドのテスト テスタブルなアーキテクチャ サーバサイドはDI+レイヤードアーキテクチャがハマりやすい Handler AWS Lambdaに依存する処理はここのみ UseCase Domain Infrastructure DynamoDB, S3など Infrastructure層は必ずDomain層に定義したInterfaceから扱う => アプリケーションの大部分(UseCase/Domain/Infrastructure)をSmall/Mediumテスト できる テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 25

26.

バックエンドのテスト Smallテスト Domain層 最も依存が少ない→最もSmallテストが容易な層 UseCase層 InfrastructureをDIしているため、スタブやモックに差し替えてのSmallテストが可 能 まずはDomain/UseCaseを集中的にテストする テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 26

27.

バックエンドのテスト Mediumテスト UseCase+Domain+Infrastructureを一気通貫で動作させる自動テスト DynamoDBやS3はDockerイメージで提供されているエミュレータを利用する LocalStack dynamodb-local + Minio コミュニティ・エコシステムに感謝 テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 27

28.

バックエンドのテスト Largeテスト APIGateway+Lambda+DynamoDBを実際にAWSにデプロイし、そのエンドポイントに リクエストを投げレスポンスをアサーションする DBの状態をアサーションすることもある 実行時間が長く不安定なため、GitHub PR毎などの実行はしない。1日1回実行 上の理由に加え、作成・メンテナンスのコストも大きめであることに留意。テストケー スは正常系操作のみなど厳選する それでもこのテストを整備する価値は大きい IAM権限の不足などを炙り出せる テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 28

29.

バックエンドのテスト ところで: サーバーレスバックエンドはテストしづらい? なぜそう言われる? => ローカル環境でAPIサーバを起動することが少々やりづらいから => テストピラミッドで考えてみる テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 29

30.

バックエンドのテスト 不安定 低速 ⾼コスト [Large] API ( 本物のAWS) サーバレスでテストしづらいと ⾔われがちなゾーン [Medium] API ( ) ローカル [Medium] UseCase+Domain+Infrastructure [Small] UseCase / Domain 安定 ⾼速 低コスト テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 30

31.

バックエンドのテスト ローカルAPIサーバテストをしなくても テストピラミッド内で占める面積はあまり大きくない その他のSMLテストを拡充させることでカバー可能と考える テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 31

32.

バックエンドのテスト ちなみに: 高速デプロイ/ローカルサーバ起動 「とはいってもコード変更→Postmanでリクエスト投げる→レスポンス見るサイクルをこ まめに回しながら開発したいな〜」 => ダイレクトに解決することもできる AWS CDKのhotswapデプロイ AWS CDKにLambda関数を数秒でデプロイするhotswap deployments機能が追加 されました デプロイ待ち時間を大幅短縮 samやserverless frameworkでローカルサーバ起動も可能(そう) SAM CLI を使ってできるだけローカルでテストしてからデプロイする ただし発表者は試したことはありません テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 32

33.

フロントエンドのテスト フロントエンドのテスト テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 33

34.

フロントエンドのテスト Reactアプリケーションにレイヤードアーキテクチャを適 用すべきか? フロントエンドアプリケーションは発表者自身まだ手探りな部分がある・・・ https://twitter.com/Nkzn/status/1220122066109657088 GraphQL + Apollo Client + React Hooksの世界では紋切り型の(よくDDDと混同しつ つ構造だけ紹介されてる)レイヤードアーキテクチャらしきものはほぼ適用できなくな るけど、それは関心の分離がないわけではなくて形が違うだけなので、SOLIDくらいま で立ち返って別の分離方法を模索することになる テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 34

35.

フロントエンドのテスト アーキテクチャ(現時点の考え) アプリケーションがReactと密結合になっても良い? 『Clean Architecture 達人に学ぶソフトウェアの構造と設計』Robert C. Martin、角征典、高 木正弘、ドワンゴ、2018 フレームワークなんかと結婚するな! おっと、フレームワークを使うことは問題ない。ただし、結合しないことが大切だ。 テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 35

36.

フロントエンドのテスト 特定のライブラリと密結合する決断もアリ? 世界一わかりやすいClean Architecture - nuits.jp blog 具体的には、次のような「上位レベルの決断」の上であれば問題ないと考えています。 そもそも自作するよりサードパーティーライブラリを利用したほうが生産性も品質も高 くなると判断でき、そのライブラリの変更が緩やかで、十分に後方互換が考慮されてい て、そのライブラリの変化をアプリケーション側で十分に許容できると判断しているよ うな場合に、Presentation内に限定して利用を許可する。 テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 36

37.

フロントエンドのテスト ライブラリ・フレームワークと密結合することのトレードオフは十分認 識した上で・・・ React(そしてHooks)の世界観に乗ってしまった方が良いというスタンスになった Reactそのものはここ5〜10年近くビューライブラリメインストリームの地位を保っ ている また、振り返ってみると機能追加はあっても破壊的変更は少なかった つまり「そのライブラリの変更が緩やかで、十分に後方互換が考慮されていて、そ のライブラリの変化をアプリケーション側で十分に許容できる」に当てはまると判 断 Hooks時代に入ってからはどうしても伝統的なレイヤードアーキテクチャとの噛み合わ せが悪いと感じる テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 37

38.

フロントエンドのテスト ただし、Reactの3rdライブラリには注意を払う 状態管理、コンポーネント集、ルーティング、CSS in JS・・・ 破壊的変更があったりトレンドの移り変わりでメンテが終了するものも多い これらの選定には慎重になる 採用実績、GitHubのメンテ状況、npm trends、npm audit出力結果・・・ また、アップグレードや乗り換え戦略は必ず考えておくこと もちろん自動テスト基盤を如何に整備するかが最重要キーになることは間違いない (でしょう) テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 38

39.

フロントエンドのテスト ところで: Next.jsは? (まだ実案件投入したことはないのですが)Next.js Wayに乗るのも超アリだと思います! AWSにホスティングする場合、決定版的選択肢が定まらないように見えるのがやや悩みどこ ろではある(全く悪いことではないですが) AppRunner AWS App Runner にSSRありの Next.js アプリをデプロイする(ソースコードデプ ロイ) Amplify Hosting - Next.js - JavaScript - AWS Amplify Docs Serverless serverless-nextjs/serverless-next.js: Deploy your Next.js apps on AWS Lambda@Edge via Serverless Components テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 39

40.

フロントエンドのテスト 話を戻して・・・ テスト方針(現時点の考え) バックエンドから受け取った情報を描画することがメイン、込み入ったロジックが少ないフ ロントエンドアプリケーションの場合 => Playwright + MSWを用いたMediumテストをメインとする (バックエンドをモック化したフロントエンド完結のUIテスト) テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 40

41.

フロントエンドのテスト その他のテスト: Utilityやただの関数として切り出しやすい処理はSmallテストする Date インスタンスのフォーマット バックエンドAPIから受け取った配列のフィルタ処理 Playwright スナップショットテスト あまり厳密にはやり過ぎず実施する CIで実行しないスナップショットテストがすごく便利 テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 41

42.

フロントエンドのテスト (今回の前提において)フロントエンドのテストは逆ピラミッドに寄りやすいと感じる 不安定 低速 ⾼コスト [Medium] UI (API ) モック [Small] Utility などの関数 安定 ⾼速 低コスト とはいえただちに問題ではない。後述します テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 42

43.

アプリケーション全体のテスト アプリケーション全体のテスト テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 43

44.

アプリケーション全体のテスト Largeテスト(自動) 本物のAWSにデプロイしたアプリケーション全体をテストする UIを操作し、期待する要素が存在することをアサーションする バックエンドLargeテストと被る観点も多い DBの状態をアサーションすることもある 実行時間が長く不安定なため、GitHub PR毎などの実行はしない。1日1回実行 上の理由に加え、作成・メンテナンスのコストも大きめであることに留意。テスト ケースは正常系操作のみなど厳選する テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 44

45.

アプリケーション全体のテスト Largeテスト(手動) 人間のユーザ視点で確認することの価値 網羅的に実施したくなるが、 ここまでの自動テストの土台があること 手動テストは実施に最も人員・時間を要すること を鑑みてできるだけケースを厳選することが望ましい とはいえ手動テストを0にすることも難しいと考えています 簡単な手動テストを実施するだけで自動テスト観点が漏れていたことに気づくこともある テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 45

46.

アプリケーション全体のテスト アプリケーション全体 テストピラミッド 不安定 低速 ⾼コスト [Large] UI (⼿動) [Large] UI (⾃動) 安定 ⾼速 低コスト テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 46

47.

まとめ まとめ バックエンド レイヤードアーキテクチャを採用する Handler/UseCase/Domain/Infrastructure Smallテスト: UseCase/Domain Mediumテスト: UseCase+Domain+Infrastructure Largeテスト: AWSにデプロイしたAPIを叩く 理想的な順ピラミッドに最も近づけやすい テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 47

48.

まとめ フロントエンド 無理にレイヤードアーキテクチャを採用しない 基本的にReact Wayに乗る 3rdライブラリは栄枯盛衰が激しいので注意 追従・乗り換え戦略は必ず持っておく Playwright+MSWを用いたMediumテストを主力とする 関数に切り出せる処理はSmallテスト対象としていく 結果的にMediumからSmallへの逆ピラミッドになる テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 48

49.

まとめ 全部合体したピラミッドがこちら 不安定 低速 ⾼コスト [Large] UI ( ) ⼿動 [Large] UI ( ⾃動) [Large] Backend API (AWS) [Medium] Frontend UI [Medium] Backend UseCase+Domain+Infrastructure 安定 ⾼速 低コスト [Small] Frontend Utility Backend UseCase / Domain フロントエンドテストの逆ピラミッドについても、アプリケーション全体としてピラミッド になっていれば許容できると考える テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 49

50.

まとめ 以上が現時点の自分の解です 異論もあるかと思います(ぜひコメントください) もちろん課題も残る テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 50

51.

今後の課題 今後の課題 (とはいってもやはり)フロントエンドのSmallテストを厚くしたい (自分の) JavaScript のユニットテストの書き方 IaCのテスト CDK素人がCDKのテスト方法について考えたのでまとめてみた | DevelopersIO テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 51

52.

参考 参考 『初めての自動テスト』Jonathan Rasmusson、玉川 紘子、オライリージャパン、2017 『Clean Architecture 達人に学ぶソフトウェアの構造と設計』Robert C. Martin、角征 典、高木正弘、ドワンゴ、2018 テストのピラミッドを開発者と一緒に眺めてみよう! | DevelopersIO Google Testing Blog: Test Sizes (自分の) JavaScript のユニットテストの書き方 質とスピード(2022春版、質疑応答用資料付き) / Quality and Speed 2022 Spring Edition - Speaker Deck テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 52

53.

参考 CIで実行しないスナップショットテストがすごく便利 Naoya ItoさんはTwitterを使っています: 「フロントを React Hooks で、 urql や Recoil を使って状態管理。一方、ヘビーな業務を処理するバックエンドの はオニオンアーキテ クチャよろしく戦術的DDD。クラス指向なOOで UseCase層あり、集約をきちんとつか ったドメインモデルと、それに応じた Repository パターンみたいに実装する (続く)」 / Twitter 架空のシステムを題材にLambda or Fargateを検討するグループティスカッションを開催 してみた | DevelopersIO テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 53

54.

参考 『ドメイン駆動設計入門』成瀬 允宣、翔泳社、2020 little-hands/ddd-q-and-a: DDD質問箱 回答記録 使用ライブラリのバージョン管理 — 仕事ですぐに使えるTypeScript ドキュメント 世界一わかりやすいClean Architecture - nuits.jp blog テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 54

55.

本スライドで利用したツール 本スライドで利用したツール marp-team/marp: The entrance repository of Markdown presentation ecosystem diagrams.net draw.ioから名前が変わったらしい テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 55

56.

謎解きクイズヒント 謎解きクイズヒント テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 56

57.

おわり おわり ありがとうございました! テストピラミッドで考える、継続するAWSサーバレスアプリケーション自動テスト@dyoshikawa 57