freeeの開発情報ポータルサイト

決済プロダクトのマジ価値を最速で届けるためのバックエンドQAの事例

こんにちは、freeeで決済プロダクトのQAエンジニアをしているrenです。freee QA Advent Calendar 2023 - Adventarの11日目です。
この記事では、決済プロダクトでアジャイルQAを実践するために取り組んでいる、バックエンドQAの事例を紹介します。

決済プロダクトで取り組んでいるアジャイルQA

決済プロダクトの開発はスクラムで行なっており、QAを含むOneTeam*1で行っています。
そのため、QAエンジニアもスクラムイベントに出ており、開発と併走できるQA活動を目指して日々仕事に取り組んでいます。

このようなQA活動をfreeeではアジャイルQAと呼んでいます。詳細な経緯や意図については、ymty-sanの記事を参照ください。 developers.freee.co.jp

スクラムのイテレーティブな開発にあわせてイテレーティブにアジャイルQAを行うことの利点は大きく3つあります。

1点目は、実装直後にテストをするため、見つかったバグの原因切り分けが容易であることです。
これは、テスト対象が基本的にそのスプリントか前スプリントの実装成果物であり、前スプリントまでに実装したものは既にテスト済みである…という状況が続くためです。
バグが入り込んだPR、もしくは顕在化させたPRの特定が容易であるため、原因切り分けもスピーディに行えます。

2点目は、プロダクト要求とシステムへの理解を着実に深め続けられることです。
テスト実行を開始する前から、PRDやDesignDocのレビュー、ストーリーチケットの受入基準作成などを行うことで、チームのプロダクト要求の理解を深めることに貢献できます。
また、スプリントごとのテスト実行を通じて、システムに対する誤解や要求との齟齬を暴くことができるため、プロダクトがマジ価値を届けられるかを常に検証できます。
逆に、システムが要求通り動くことを確かめ続けるとも言えるため、安心を積み上げていくことができます。

3点目は、実装完了後からリリースまでの時間(リードタイム)を短縮できることです。
リリースしたいフィーチャーが実装完了する頃にはほぼほぼテストが終わっているため、あとはe2eテストやリグレッションテストを実施すればOKという状況になります。
実際私たちのチームでは、多くの場合実装完了後から3営業日程度でテストやバグ修正が完了し、リリース可能な状態を迎えています。

このような利点をもつアジャイルQAを実現するために、決済プロダクトではバックエンドQAを実践しています。

バックエンドQAで行なっていること

freeeではバックエンドに焦点を当てたテスト活動をバックエンドQAと呼んでおり、具体的には以下のような活動をしています。

  • バックエンド開発を管理するストーリーチケットの受入基準作成と、チームへのフィードバック
  • 早期からのAPIテスト
  • バッチ処理やUI操作を伴うテストにおける、DB検証

ここからは、どのようにバックエンドQAの活動を行っているのかを説明します。

バックエンド開発を管理するストーリーチケットの受入基準作成と、チームへのフィードバック

ストーリーチケットは、エンドユーザーの体験や生み出す価値を表すユーザーストーリーに対応させて作成するものですが、私たちのチームでは、ストーリーによって、フロントエンド側とバックエンド側でストーリーチケットを切り分けています。これは、進捗の見えやすさやテストの入りやすさを向上させるためです 。

また、ストーリーチケットの受入基準をQAエンジニアが書いています。これは、ユーザーストーリーをテスト対象としたとき、テスト分析のアウトプットとして受入基準がぴったりだと考えているためです。フロントエンド側とバックエンド側で切り分けている場合は、それぞれに対して受入基準を作成します。

バックエンド開発を管理するストーリーチケットの受入基準には、例えば以下のような文章が書かれます。

ストーリーA:参照処理を含むストーリーの場合

- エンドポイントA(/api/xxxx/yyyy/{id})に対して、自事業所の取引idを指定してGETリクエストを実行したとき、レスポンスとして取引情報を得られること
- エンドポイントAに対して、他事業所の取引idを指定してGETリクエストを実行したとき、エラーレスポンスが返ってきて取引情報を得られないこと
- エンドポイントAに対して、存在しない取引idを指定して GETリクエストを実行したとき、異常終了せずエラーレスポンスが返ってくること

ストーリーB:外部システムからのリクエストと、その後続処理を含むストーリーの場合

- 外部システムからエンドポイントBに対してステータス通知リクエストが飛んできた場合、リクエストbodyの中身に従って、テーブルBとテーブルCのレコードを更新すること
- リクエストの内容とDBの状態に不整合がある場合、レコードの更新を行わないこと。また、BugSnag(エラートラッキングサービス)が発火すること
  - ※どのような場合に不整合と見なすかは、状態遷移図を参照

このような受入基準を作成したら、チーム全体に共有し、認識齟齬がないかを確かめます。
たとえば、更新処理の条件に関する認識齟齬がある場合、上記のリクエストの内容とDBの状態に不整合がある場合、レコードの更新を行わないこと。また、BugSnagが発火することが受入基準として明文化してあることで、「どのような事前条件・入力の場合に不整合と見なすのか」について改めて整理する機会を得られ、実装に入る前にバグの原因を取り除くことができます。

これらはDesignDocのレビューでも拾える可能性があるものですが、ユーザーストーリーに沿ってバックエンドに期待する動きを再記述することで、詳細な議論・レビューが可能になると考えています。

そして、このように作成したバックエンドに対する受入基準をもとに、後述するAPIテストのテスト設計と実行を進めていきます。

早期からのAPIテスト

APIテストとは、テスト対象のAPIを直接叩くことで実施するテストを指します。
直接バックエンドをテストする手段として、またできるところからどんどんテストするための手段として、とても重要であり、注力している部分でもあります。

freeeではプロダクトやユースケースによって複数のAPIプロトコルが採用されており、REST APIの場合はPostmanやcurlといったAPIクライアントツールを用いて、 gRPCの場合はevansやgRPCurlといったgRPCクライアントツールを用いてテストを行っています。

APIテストとしての基本的な考え方は同じであるため、本記事ではgRPCのテストを例に紹介します。

gRPCのテスト

上述した受入基準作成やテスト設計を行うにあたり、関係するパラメータを洗い出すために、DesignDocやprotoファイル、schemaファイルを見に行っています。

protoファイルとは、gRPCのrpc定義とリクエスト・レスポンスのスキーマ定義を記述したファイルであり、以下のように記述されます。(参照:https://protobuf.dev/programming-guides/proto3/#services, https://protobuf.dev/programming-guides/proto3/#enum

service SearchService {
  rpc Search(SearchRequest) returns (SearchResponse);
}
enum Corpus {
  CORPUS_UNSPECIFIED = 0;
  CORPUS_UNIVERSAL = 1;
  CORPUS_WEB = 2;
  CORPUS_IMAGES = 3;
  CORPUS_LOCAL = 4;
  CORPUS_NEWS = 5;
  CORPUS_PRODUCTS = 6;
  CORPUS_VIDEO = 7;
}

message SearchRequest {
  string query = 1;
  int32 page_number = 2;
  int32 results_per_page = 3;
  Corpus corpus = 4;
}

上記の場合、

  • Searchというrpcメソッドがある(rpcサービスとは、gRPCにおけるAPI定義のことで以降APIと記載します。)
  • SearchのインプットはSearchRequestである
  • SearchRequestは、query, page_number, results_per_page, corpusで構成される
  • corpusには特定の値が入り、その特定の値とはCORPUS_UNSPECIFIED, CORPUS_UNIVERSALなどである

ということが分かります。このようなprotoファイルから、APIの概要の知識を得ます。

また、protoファイルからは読み取れないAPI同士の処理順序や関連テーブルを知るため、DesignDocを確認します。
そして、DBのschema定義からは外部キー制約やnull値を許容するかなどを知ることができるため、テスト対象のAPIに関連するテーブルのschemaもなるべく確認しにいきます。

さらに、実装が並行して進んでいる場合は、実装も確認します。どの順序でパラメータが扱われているかを知ることで、デシジョンテーブルテストなどに役立てることができるからです。(実装されているロジックを鵜呑みにするとそのロジック自体の検証ができなくなるので、あくまで求められている動きをもとにロジックを整理し、実装は有則な組み合わせテストのケース圧縮の参考情報として用います)

このように情報収集しロジックを整理した後、下記のようなテストケース表を作成してAPIテストを実行します。

APIをテストするときに利用するテストケース表

テスト実行の際は、開発エンジニアと同じように開発環境を作ってそこでAPIを叩いたり、社内のテスト環境を用いてAPIを叩いたりしています。実行結果の確認では、APIレスポンスやAPI実行前後のDBを見ています。
開発環境の方が容易に関連プロダクトのDBを見に行ける事情もあり、決済プロダクトのQAエンジニアは全員開発環境を構築しています。

(gRPCのテストの場合、evansを用いることが多いです。ツールの使い方については、ktr0731-sanの記事で分かりやすく解説されているので、こちらを参照ください)engineering.mercari.com

バッチ処理やUI操作を伴うテストにおける、DB検証

アジャイルQAの趣旨とは少し離れますが、バックエンドQAで行なっていることとして紹介します。

決済プロダクトでは、申込みにおける審査処理や外部システムへのリクエストにrate limitがある都合上、多くのバッチ処理が存在しています。
このようなバッチ処理の結果更新されるDBの内容は、UIに表示されるものもありますが、表示されないものもあります。データの欠損や不整合は重大なインシデントにつながるリスクが高いため、ちゃんとテストし切るために、DBを確認しています。

また決済プロダクトでは、ウェブコンポーネントを採用している社内の基盤マイクロサービスを利用しており、フロントエンドから基盤マイクロサービスのAPIを叩くことがあります。
このような場合も、UIの表示が更新されることだけでなく、関連テーブルを全て更新できているかをテストするため、DBを確認しています。

まとめ

  • バックエンドQAによって、システムを動かすための手段が増え、より早くテストできるようになる
  • より早くテストすることは、バグ原因の切り分けの容易さやリリース直近のテスト工数圧縮など、大きなメリットがある
  • バックエンドQAには、早さのメリットだけではなく、データの欠損や不整合などをより確実に検出できるメリットがある

決済プロダクトのマジ価値を最速で届けるために取り組んでいる、バックエンドQAの事例を紹介しました。
freee QAは、より品質の高いプロダクトをより早く届けるために、挑戦を続けていきます。

明日は、nun-sanがテスト管理ツールの比較について記事を書いてくれます。楽しみですね!
最後まで読んでいただきありがとうございました。それでは、良い品質を〜

*1:「Quality Assurance to Agile Quality」という、アジャイル開発において効率的かつ効果的に品質保証を進めるために有用な実証済みのパターン集があり、「QAを含むOneTeam」はそのうちの一つです。参考:品質のアジャイルなあり方:「QAを含むOneチーム」「品質スプリント」「プロダクト品質チャンピオン」 (1/3)|CodeZine(コードジン)