Upgrade to Pro — share decks privately, control downloads, hide ads and more …

スナップショットログを用いた自動E2Eテストの導入 / JJUG_CCC_2022

スナップショットログを用いた自動E2Eテストの導入 / JJUG_CCC_2022

2022/06/19_JJUG CCC 2022 Springでの、中里/小谷野/濱岡の講演資料になります

85da685d91fda190e2e3162d0de248a4?s=128

Recruit
PRO

June 28, 2022
Tweet

More Decks by Recruit

Other Decks in Technology

Transcript

  1. (C) Recruit Co., Ltd. All rights reserved. (C) Recruit Co.,

    Ltd. All rights reserved. スナップショットログを用いた 自動E2Eテストの導入 Naoto Nakazato / Yuji Koyano / Yusuke Hamaoka @JJUG CCC 2022 Spring
  2. (C) Recruit Co., Ltd. All rights reserved. NAKAZATO Naoto 中里

    直人 株式会社リクルート ホットペッパービューティー プロダクト開発2グループマネージャー ホットペッパービューティーの開発組織を担当し ています Hazy IPAが好きです 2
  3. (C) Recruit Co., Ltd. All rights reserved. KOYANO Yuji 小谷野

    雄史 株式会社リクルート ホットペッパービューティー モバイル向けAPI開発チームリーダー クラフトビールとKotlinが好きです 3
  4. (C) Recruit Co., Ltd. All rights reserved. 4 HAMAOKA Yusuke

    濱岡 佑介 株式会社リクルート ホットペッパービューティー モバイル向けAPI開発チーム 山とか自然が好きです
  5. (C) Recruit Co., Ltd. All rights reserved. 本日お話しする内容 1. E2Eテスト自動化の取り組み

    2. スナップショットロギングテストの実装 3. スナップショットロギングテストの運用方法 4. 導入効果 5
  6. (C) Recruit Co., Ltd. All rights reserved. (C) Recruit Co.,

    Ltd. All rights reserved. 1. E2Eテスト自動化の取り組み 6 6
  7. (C) Recruit Co., Ltd. All rights reserved. ホットペッパービューティーとは ヘアサロン、リラクゼーション&ビューティサロンの検索・予約ができる国内最大級のサービス 年間約1億4500万回の予約が行われる(2022年5月時点)

    Web版とアプリ版が存在するが、今回はアプリ用APIのお話 https://beauty.hotpepper.jp/doc/guide/saishindata.html 7
  8. (C) Recruit Co., Ltd. All rights reserved. アプリ用APIのシステム構成 他システム DB、検索エンジン、外部API等

    8 BFF Backend モバイルアプリ用のAPIはBFF(Backends For Frontends)とBackendの2段構成 BFFはSpring Webflux、BEはSpring MVCを利用 https://www.slideshare.net/RecruitLifestyle/apibffbackend-146832033
  9. (C) Recruit Co., Ltd. All rights reserved. アプリ用APIのシステム構成 他システム DB、検索エンジン、外部API等

    9 BFF Backend APIサーバー 今回はここのお話
  10. (C) Recruit Co., Ltd. All rights reserved. アプリ用APIが抱える課題 アプリ用APIのライブラリのアップデートや大規模リファクタリングは影響範囲 が広いため、全ての機能を手動でテストするルールにしていた

    → これには当然大きな工数がかかるため頻繁に行うことはできない 10
  11. (C) Recruit Co., Ltd. All rights reserved. アプリ用APIが抱える課題 一方でiOS /

    Androidでは1年に1回、新OS向けの対応を実施していて、 そこでも全ての機能を手動でテストしていた 新OS対応と同じタイミングでライブラリアップデートや大規模リファクタリング を実施することで、テスト工数の節約をしていた 11 iOS Android API 新OS対応と スルーテスト 1月 12月 新OS対応と スルーテスト 大規模アップデート 大規模アップデート
  12. (C) Recruit Co., Ltd. All rights reserved. しかしこの運用には以下のような課題があった • iOSとAndroidの年2回しかテスト実施のチャンスがない

    別途テスト実施する場合は大きな工数がかかる • アプリとAPIでスケジュールを調整する必要がある 新OS対応では予期せぬ問題が発生するためスケジュールが組みにくい • バグ検出時にアプリとAPIのどちらに原因があるのか特定しづらい アプリ用APIが抱える課題 12
  13. (C) Recruit Co., Ltd. All rights reserved. 解決策の検討 13 解決策を検討するにあたり、下記2点が前提として存在していた

    • 美容業界のインフラとして品質を保つため、テストは必須 • 現行の全機能手動テストはとても時間がかかる → テストの自動化によるテスト工数削減を検討した
  14. (C) Recruit Co., Ltd. All rights reserved. テスト自動化の具体手法検討 14 選択肢

    ホットペッパービューティーでの評価 JUnitでUnitTestを担保する UnitTestはすでに実装済みだが、E2Eの観点が足りない Integration Testを実装する システム規模が大きくスルーテストケース数が4,000以上あるため、 それらを新規で実装・メンテナンスしていくのは大変 アプリの自動テストツールを使う 上記に加えて、Flakyになりやすい Snapshot Logging Testを使う 完全自動化はできないがテストが必要な箇所を絞り込める(後述) 今回はSnapshot Logging Testを採用!
  15. (C) Recruit Co., Ltd. All rights reserved. 今回採用した手法のまとめ 15 •

    アプリ新OS対応のテスト時に、スナップショットログを全て保存 • 後でこれを再生・検証することでテストの大部分を自動化 これによりアプリと独立して頻繁なアップデートを安全に実施することを目指す アプリの新OS対応 継続して全機能の手動テスト テスト対象がAPIに限定される対応 ライブラリアップデート、大規模リファクタリング 自動化対象
  16. (C) Recruit Co., Ltd. All rights reserved. 今回採用した手法 他システム DB、検索エンジン、外部API等

    手動QA実行時 他システム モック 自動E2Eテスト実行時 テスト実行 クライアント 読み込み 生成 記録 記録 16 BFF Backend APIサーバー(テスト対象) BFF Backend APIサーバー(テスト対象) スナップショット ログ
  17. (C) Recruit Co., Ltd. All rights reserved. (C) Recruit Co.,

    Ltd. All rights reserved. 2-1. スナップショットロギングテストの実装 -ログの取得- 17 17
  18. (C) Recruit Co., Ltd. All rights reserved. スナップショットログ取得 他システム DB、検索エンジン、外部API等

    手動QA実行時 記録 記録 BFF Backend APIサーバー(テスト対象) 他システム モック 自動E2Eテスト実行時 テスト実行 クライアント 読み込み 生成 BFF Backend APIサーバー(テスト対象) スナップショット ログ 18
  19. (C) Recruit Co., Ltd. All rights reserved. • エンドポイント •

    HTTPメソッド • クエリパラメータ • リクエストボディ • レスポンスデータ • traceId • 時刻 スナップショットログの内容 他システム DB、検索エンジン、外部API等 手動QA実行時 記録 記録 19 スナップショット ログ BFF Backend APIサーバー(テスト対象) • クラス名 • メソッド名 • 外部システムのコール回数 • 返却データ • traceId • 時刻 • クラス名 • メソッド名 • 外部システムのコール回数 • 返却データ • traceId • 時刻 • クラス名 • メソッド名 • 外部システムのコール回数 • 返却データ • traceId • 時刻
  20. (C) Recruit Co., Ltd. All rights reserved. • エンドポイント •

    HTTPメソッド • クエリパラメータ • リクエストボディ • レスポンスデータ • traceId • 時刻 アプリ・BFF間のスナップショットログ取得の実装 他システム DB、検索エンジン、外部API等 手動QA実行時 記録 記録 20 スナップショット ログ Backend • クラス名 • メソッド名 • 外部システムのコール回数 • 返却データ • traceId • 時刻 BFF APIサーバー(テスト対象) HTTPリクエストとレスポンスの情報を取得したいので、素直にWebFilterを実装
  21. (C) Recruit Co., Ltd. All rights reserved. • エンドポイント •

    HTTPメソッド • クエリパラメータ • リクエストボディ • レスポンスデータ • traceId • 時刻 Backend・他システム間のスナップショットログ取得の実装 他システム DB、検索エンジン、外部API等 手動QA実行時 記録 記録 21 スナップショット ログ BFF APIサーバー(テスト対象) AOP(AspectJ)を利用し、各処理のログを記録 Backend • クラス名 • メソッド名 • 外部システムのコール回数 • 返却データ • traceId • 時刻 • クラス名 • メソッド名 • 外部システムのコール回数 • 返却データ • traceId • 時刻 • クラス名 • メソッド名 • 外部システムのコール回数 • 返却データ • traceId • 時刻
  22. (C) Recruit Co., Ltd. All rights reserved. 他システム DB、検索エンジン、外部API等 手動QA実行時

    記録 記録 スナップショット ログ BFF Backend APIサーバー(テスト対象) ログファイルの紐付け 22 • クラス名 • メソッド名 • 外部システムのコール回数 • 返却データ • traceId • 時刻 • クラス名 • メソッド名 • 外部システムのコール回数 • 返却データ • traceId • 時刻 • クラス名 • メソッド名 • 外部システムのコール回数 • 返却データ • traceId • 時刻 • エンドポイント • HTTPメソッド • クエリパラメータ • リクエストボディ • レスポンスデータ • traceId • 時刻 同一リクエスト内の一連のログをどう紐づけるか
  23. (C) Recruit Co., Ltd. All rights reserved. 分散トレーシングのtraceId • traceId:一連の呼び出しに割り当てられるID。

    • spanId: 作業単位に割り当てられるID。 W3CやOpenTelemetryで同様の仕様が定義されている 23 Client BFF Backend 他システム traceId: X spanId: A traceId: X spanId: B traceId: X spanId: C traceId: X spanId: D 一連の呼び出しの中でtraceIdは同一 → これを用いてログを紐付ける https://www.w3.org/TR/trace-context/ https://opentelemetry.io/docs/reference/specification/trace/api/
  24. (C) Recruit Co., Ltd. All rights reserved. Spring Cloud Sleuthの利用

    • Spring Cloud Sleuthにより分散トレーシングを実現 • MDC(Mapped Diagnostic Contexts)の設定で、traceIdを簡単にログ出力可能 24
  25. (C) Recruit Co., Ltd. All rights reserved. 他システム DB、検索エンジン、外部API等 手動QA実行時

    記録 記録 スナップショット ログ BFF Backend APIサーバー(テスト対象) コンテキスト情報の補完 25 • クラス名 • メソッド名 • 外部システムのコール回数 • 返却データ • traceId • 時刻 • クラス名 • メソッド名 • 外部システムのコール回数 • 返却データ • traceId • 時刻 • クラス名 • メソッド名 • 外部システムのコール回数 • 返却データ • traceId • 時刻 • エンドポイント • HTTPメソッド • クエリパラメータ • リクエストボディ • レスポンスデータ • traceId • 時刻 ログファイルにコンテキスト情報を載せたい
  26. (C) Recruit Co., Ltd. All rights reserved. コンテキスト情報の補完 Webアプリケーションの応答は、下記の3つによって決定される 1.

    入力内容 2. 外部システムの挙動 3. コンテキスト情報 他システム DB、検索エンジン、外部API等 手動QA実行時 BFF Backend APIサーバー(テスト対象) スナップショット ログ 記録 記録 1. 入力内容 2. 外部システムの挙動 26
  27. (C) Recruit Co., Ltd. All rights reserved. コンテキスト情報の補完 Webアプリケーションの応答は、下記の3つによって決定される 1.

    入力内容 2. 外部システムの挙動 3. コンテキスト情報 1.2.に加え、3.もログでキャプチャすることで再現性を上げたい 本手法では主なコンテキストとして時刻をキャプチャ =現在時刻に依存した処理があるため 27
  28. (C) Recruit Co., Ltd. All rights reserved. (C) Recruit Co.,

    Ltd. All rights reserved. 2-2. スナップショットロギングテストの実装 -テストの実行- 28 28
  29. (C) Recruit Co., Ltd. All rights reserved. 自動E2Eテストの実行方法 他システム DB、検索エンジン、外部API等

    手動QA実行時 記録 記録 29 BFF Backend APIサーバー(テスト対象) 他システム モック 自動E2Eテスト実行時 テスト実行 クライアント 読み込み 生成 BFF Backend APIサーバー(テスト対象) スナップショット ログ
  30. (C) Recruit Co., Ltd. All rights reserved. テスト実行クライアント 30 他システム

    モック 自動E2Eテスト実行時 テスト実行 クライアント 読み込み 生成 BFF APIサーバー(テスト対象) スナップショット ログ Backend ログを読み込み実行 エンドポイントごとに結果レポートを出力
  31. (C) Recruit Co., Ltd. All rights reserved. テスト実行クライアントの実装 31 ログを読み込み、

    traceIdを載せリクエストを飛ばし、 レスポンスをログ内容と比較する エンドポイントごとに結果レポートを出力する
  32. (C) Recruit Co., Ltd. All rights reserved. 他システムのモック 32 他システム

    モック 自動E2Eテスト実行時 テスト実行 クライアント 読み込み 生成 Backend スナップショット ログ BFF APIサーバー(テスト対象) ログから他システムのモックを生成
  33. (C) Recruit Co., Ltd. All rights reserved. 他システムのモックの実装 33 traceId+メソッド名+実行回数を

    キーとしたMapを元に レスポンスデータを返却するモックを生成
  34. (C) Recruit Co., Ltd. All rights reserved. (C) Recruit Co.,

    Ltd. All rights reserved. 3. スナップショットロギングテストの運用方法 34 34
  35. (C) Recruit Co., Ltd. All rights reserved. ログ取得モードとモックモードの切替 他システム DB、検索エンジン、外部API等

    手動QA実行時 記録 記録 35 BFF Backend APIサーバー(ログ取得モード) configファイルの設定により ログ取得モード・モックモードを 切り替える 他システム モック 自動E2Eテスト実行時 テスト実行 クライアント 読み込み 生成 BFF Backend APIサーバー(テスト対象) スナップショット ログ
  36. (C) Recruit Co., Ltd. All rights reserved. テストケースの管理 他システム DB、検索エンジン、外部API等

    手動QA実行時 記録 記録 36 BFF Backend APIサーバー(テスト対象) GCP BigQuery 取り込み SQLで集計 Google Spreadsheet スナップ ショットログ Amazon S3
  37. (C) Recruit Co., Ltd. All rights reserved. ログを集計してテストケースを把握しやすくする 37 エンドポイント毎の

    テストケースの本数 APIエンドポイント クエリパラメータ /salon/100/stylists type=beginner /salon/200/stylists date=2022-05-22&start=0 /salon/300/stylists start=10&count=20 API名 APIエンドポイント HTTPメソッド テストケース数 サロン取得API /salons/{id} GET 45 スタイリスト一覧取得 API /salon/{id}/stylists GET 30 予約一覧取得API /resevations GET 20 エンドポイント毎の テストケースの詳細 ex. スタイリスト一覧取得 API GCP BigQuery 取り込み SQLで集計 Google Spreadsheet スナップ ショットログ Amazon S3
  38. (C) Recruit Co., Ltd. All rights reserved. 自動E2Eテストの実行環境 38 テスト実行

    クライアント ログファイルの配置 GCP BigQuery 取り込み SQLで集計 Google Spreadsheet スナップ ショットログ Amazon S3 AWS上に用意したテスト環境にスナップショットログを配置してE2Eテストを実行 テストの実行時間は4,000テストケースで約10分 他システム モック BFF Backend APIサーバー(テスト対象)
  39. (C) Recruit Co., Ltd. All rights reserved. 自動E2Eテストの実行タイミング 39 releaseブランチ

    developブランチ featureブランチ 機能開発・改善 QA実施 バグ修正 ・ リリース テストサイズの大きさから リリースブランチに変更が加わったタイミングで自動E2Eテストを実施
  40. (C) Recruit Co., Ltd. All rights reserved. 自動E2Eテストの結果レポート 40 テスト実行

    クライアント GitHub 結果レポートをコミット Slack テスト結果を通知 詳細の確認 概要の確認
  41. (C) Recruit Co., Ltd. All rights reserved. Ignoreするテストケースの管理 41 API名

    APIエンドポイント HTTPメソッド Ignoreフラグ サロン取得API /salons/{id} GET FALSE スタイリスト一覧取得 API /salon/{id}/stylists GET TRUE 予約一覧取得API /resevations GET TRUE エンドポイント毎に テストケースを Ignoreするかを設定 テスト実行クライアントは自動E2Eテストの実行時に設定を参照して APIのインターフェイスが変更しているなど デグレ以外の理由でFAILするテストケースをIgnoreできるようにする GCP BigQuery 取り込み SQLで集計 Google Spreadsheet スナップ ショットログ Amazon S3
  42. (C) Recruit Co., Ltd. All rights reserved. Ignoreするテストケースの管理 42 API名

    APIエンドポイント HTTPメソッド Ignoreフラグ サロン取得API /salons/{id} GET FALSE スタイリスト一覧取得 API /salon/{id}/stylists GET TRUE => FALSE 予約一覧取得API /resevations GET TRUE => FALSE エンドポイント毎に テストケースを Ignoreするかを設定 定期的な手動E2Eテストの実施タイミングで スナップショットログを再取得して 全てのテストケースを有効化する GCP BigQuery 取り込み SQLで集計 Google Spreadsheet スナップ ショットログ Amazon S3
  43. (C) Recruit Co., Ltd. All rights reserved. Ignoreするテストケースの更新 43 スナップログ取得時とE2Eテスト対象のAPIのインターフェースの差分を

    OpenAPITools/openapi-diffで検知することで どのエンドポイントのテストケースをIgnoreするかを判断する OpenAPIのJSON Google Spreadsheet 手動でIgnoreする テストケースを反映 API名 APIエンドポイント HTTPメソッド Ignoreフラグ サロン取得API /salons/{id} GET FALSE スタイリスト一覧取得 API /salon/{id}/stylists GET FALSE => TRUE 予約一覧取得API /resevations GET FALSE テスト実行 クライアント BFF OpenAPI スキーマ JSONを取得して I/F変更を自動検知
  44. (C) Recruit Co., Ltd. All rights reserved. Ignoreするテストケースの更新 44 OpenAPIのJSON

    Google Spreadsheet API名 APIエンドポイント HTTPメソッド Ignoreフラグ サロン取得API /salons/{id} GET FALSE スタイリスト一覧取得 API /salon/{id}/stylists GET FALSE => TRUE 予約一覧取得API /resevations GET FALSE テスト実行 クライアント BFF OpenAPI スキーマ しかし、インターフェイスの変化の検知だけでは 仕様が変わるテストケース全てを把握できるわけではない点に注意 その場合は手動で把握・更新しなければならない 手動でIgnoreする テストケースを反映 JSONを取得して I/F変更を自動検知
  45. (C) Recruit Co., Ltd. All rights reserved. Jacoco Agentによる自動E2Eテストのテストカバレッジ率の取得 テスト実行

    クライアント 45 Jacoco Agent Jacoco Agent Jacocoカバレッジ レポートの連携 自動E2Eテスト実行時にアプリケーションにJacoco Agentを連携することで Runtimeでテストカバレッジを取得する • E2Eテストケースのカバレッジ率(C1, C2) • Ignoreするテストケースの増加によるカバレッジ率の遷移 を把握することが可能 他システム モック BFF Backend APIサーバー(テスト対象)
  46. (C) Recruit Co., Ltd. All rights reserved. (C) Recruit Co.,

    Ltd. All rights reserved. 4. 導入効果 46 46
  47. (C) Recruit Co., Ltd. All rights reserved. 導入効果 47 →

    12 営業日 2.4 営業日 1回のテスト実施にかかる日数 → 2 回/年 6 回/年 大規模アップデート頻度 (予定)
  48. (C) Recruit Co., Ltd. All rights reserved. 自動テストが可能な機能の割合 テストケース数 100%

    手動E2Eテスト実施 80% 2ヶ月後 20% 時間 48 新規追加された機能 改修により失敗した機能 改修後も成功した機能 様々な改修 手動テスト が必要 手動テスト が不要 🎉
  49. (C) Recruit Co., Ltd. All rights reserved. 今後のテストケース数の推移イメージ テストケース数 0ヶ月後

    2ヶ月後 時間 49 成功する機能は時間とともに減少するが、半年に1回の手動テストによりテストケースを作り直す 4ヶ月後 8ヶ月後 6ヶ月後 iOSの新OS対応と 全画面手動テスト実施 Androidの新OS対応と 全画面手動テスト実施
  50. (C) Recruit Co., Ltd. All rights reserved. まとめ 50 •

    高頻度な大規模リリース目指しスナップショットロギングテストを実装 • テスト工数を5分の1に削減し、大規模リリース頻度を3倍に増やせる見込み 大規模システムを運用していて多くのテストケースを管理されている方は、 本セッションを参考にスナップショットロギングテストを試していただけると嬉しいです
  51. (C) Recruit Co., Ltd. All rights reserved. We are hiring!!

    51