バッチ処理のリグレッションテスト自動化のトライ

はじめに

この記事は、Merpay Tech Openness Month 2022 の7日目の記事です。
こんにちは。メルペイのBackendエンジニアの@kaznishiです。
この記事では、私が所属しているチームで担当している加盟店精算のマイクロサービスにおけるバッチ処理のリグレッションテスト自動化の取り組みを紹介します。
まだBackendエンジニアしかテストシナリオの整備ができるようになっていなかったり、開発フローが整備しきれているわけではないですが、現時点でどのようなテストを回しているか、そして今後どのように改良していきたいかを述べたいと思います。

前提知識

加盟店精算のマイクロサービスの性質として、毎月決まったタイミングでの締め処理があります。この締め処理の中で、メルペイを導入してくださっている加盟店さまの売上を集計し、加盟店さまの銀行口座へ振込する金額の計算を行っています。この処理は毎月決まったタイミングで行われるため、バッチにより実現されています。加盟店精算マイクロサービスにおいてはこの締めのバッチ処理が非常に重要度が高く、コアな部分です。
よって、QAの際にもバッチ処理のリグレッションテストを実施してもらうことは非常に重要です。ただ、バッチ処理のQAは事前にDBにテストデータを手動でInsertしてもらい、KubernetesのJobをkubectlコマンドを使って実行、実行後のDBの中身を目でチェックしてもらうという非常にコストが高いものになっています。
また、締め処理バッチの前後のバッチ処理と依存関係があり、バッチ処理を順番に実行して正しい状態になるかを検証するのも重要であり、その場合はさらにテストのコストが高くなります。
ちなみに、Backendエンジニア観点ではテストコードが別途実装されており、ローカルマシンおよびCIマシン上でバッチ処理のテストが行われています(ただしテストでは他のマイクロサービスはスタブ化されものがコールされます)。

メルペイのQA自動化に関する全社をあげた取り組み

メルペイでは、QAエンジニアが限られた人数でも効率的に品質を維持して高速に開発を進めていくため、QAの効率化、自動化が全社レベルでも優先度の高い項目として位置づけられていました。
その取り組みの一環として、Scenarigoを使ったAPIのテスト自動化の基盤も構築され、社内に広められました(Scenario Testing to Improve Product Quality at Merpay)。
しかし、ScenarigoはAPIをコールするテストは記述できるものの、バッチ処理の実行に関しては対応していないのと、関連するテーブルのレコードをバッチ処理前の状態でセットアップする仕組みなどは提供されていないため、加盟店精算マイクロサービスのコアとなるバッチ処理のテストをこの仕組みを使って実施することは難しいものでした(ちなみに現在ではチームによってはDebug用のAPIを生やしてScenarigoのテスト自動化基盤の拡張を書いてバッチ処理のテストを回している事例もあるようです)。
そこで、私達のチームでは独自にバッチ処理の自動テストを回す仕組みの構築を目指すことにしました。次のセクションでは現時点の加盟店精算マイクロサービスのバッチ処理のリグレッションテストを仕組みを解説します。

現時点の加盟店精算マイクロサービスのバッチ処理のリグレッションテスト自動化の仕組み

現時点の加盟店精算マイクロサービスのバッチ処理のリグレッションテストの仕組みを解説するにあたって、まずはその前提として、メルペイがサービスとして動作している環境の種類について触れておきます。
メルペイの全マイクロサービスが立ち上がっており、相互に接続してサービス全体として動作するKubernetesクラスタの環境は2種類あります。ひとつは当たり前ですが本番環境です。もうひとつが開発環境(以下、Dev環境と表記します)です。厳密に言えば、ローンチ前などに外部から試験的に接続できる環境もあるのですが、これはマイクロサービスによっては存在していなかったりします。QAはDev環境を使って行われます。
このDev環境では各マイクロサービスでAPIの自動テストが定期的に実行されていたり、新たに開発、改修された項目の手動QAが行われたりします。私達のバッチ処理のリグレッションテスト自動化の仕組みとしては、テストケース毎に加盟店精算DBの中身をクリーンにして次のテスト用のデータをInsertしたりということをやりたかったので、Dev環境DBを使うわけにはいきませんでした(他のマイクロサービスでのテスト実施に影響するため)。そこで加盟店精算マイクロサービス独自に自動リグレッションテスト用DBを立てることにし、自動リグレッションテストのJob PodからはそのDBに接続するようにしました。Job Podが他マイクロサービスをコールする際にはDev環境に接続します。
以上のような環境を用意し、1.初期データの登録、2.Dev環境KubernetesクラスタへのAPIコール、3.Job Podの立ち上げ、4.Jobの実行、5.実行終了後のDBの中身のAssertion、実行後データのクリーンアップ(これは次のテスト時に初期データ登録前に行う)といった一連の流れをMakefileのコマンド一発で実行できる仕組みをBackendエンジニア側で実装しました。
20220412-try-batch-regression-test-automation
ちなみにこの仕組みはgo testを使って動作するようになっており、Job Podの操作はk8s.ioのクライアントライブラリを使用しています(このあたりはkubectlのコマンドでも代用できると思います)。
また、go testの実装の中で複数のJobを指定の順番に実行するようにシナリオを記述することもできるので、加盟店精算マイクロサービスの前提知識のセクションで述べた、前後のバッチ処理の依存も含めてシナリオテストをすることもできます。
この仕組みをまずはQAエンジニアのローカルマシンから実行できるようにしました。そして、将来的にはCIマシンからmakeコマンドを使ったバッチ処理の自動リグレッションテストを実施できればよいなと思っています。

現在の状況と課題

現在の加盟店精算マイクロサービスのQAにおけるリグレッションテストの実施状況ですが、QAエンジニアのローカルマシンからmakeコマンドによるテストの実施は行われています。ただ、それだけでリグレッションテストが十分かというと、そうではないというのが正直なところです。現在加盟店精算マイクロサービスでは大きな開発プロジェクトが走っており、新しいバッチ処理も増え、既存のバッチ処理にも改修が走っています。その変化に自動リグレッションテストのメンテナンスが追いついていないという状況になっています。
これには設計面の要因があると思います。

現時点では、QAエンジニアのテストケースをとりあえず自動化できればOK、と必要最低限のことのみ考慮された実装になっており、QAエンジニアが自分でテストケースを拡充したりメンテナンスをしたりできるようになっていません。テストシナリオ自体がそれぞれGoで記述されており、シナリオのメンテナンスを行うにはGoの実装が必須になってしまっています。また、初期データとAssertionのための想定データはテーブル毎にYAMLで記述できるようになってはいるものの、シナリオの種類毎にどのテーブルのデータを用意すればよいかが異なっており、YAMLの準備にはシナリオの実装を読み解く必要があり、またドキュメント化もされていないため、Backendエンジニアのサポートを必要とします。
これは、どこまでの仕組みが構築できるかの実現可能性が最初の時点で不透明だったため、そのときに存在しているバッチ処理が半自動化できていればよい、というところをひとまずのゴール地点としてプロジェクトを進行した経緯があったのも要因です。

今後どうしていきたいか

シナリオに関してGoでプログラミングするのではなく、既に社内で普及しているScenarigoを使ったAPIの自動テストの仕組みと同じように、YAMLでシナリオを記述できる仕組みを提供していきたいです。Backendエンジニア側として実装するのは、初期データのDB Insert、コマンドを柔軟に指定できる形でのJob Podの実行、結果データのAssertionを、それぞれYAMLに記述されたシナリオを読み込んで実行できる仕組みという感じに抽象化していき、シナリオの記述をBackendエンジニア以外でもできるようにしていきたいです。我々のチームでこの仕組みを作り始めたときにはバッチ処理のリグレッションテストのノウハウがない状態でどこまでの仕組みが構築できるのか不透明な状況でしたが、今では社内事例も増えてきた(【書き起こし】リグレッションテストの自動化を段階的に実装した話 – 高野 純知【Merpay Tech Fest 2021】)ので、うまく他チームからもノウハウを取り入れられたらと思っています。

まとめ

ここまで、私達のチームで取り組んできたバッチ処理のリグレッションテスト自動化についての取り組みの現況と今後の改良点について紹介しました。この記事がバッチ処理の自動テストの構築プロジェクトの参考になれば幸いです。

次回の記事は myajiri さんです。引き続きお楽しみください。

  • X
  • Facebook
  • linkedin
  • このエントリーをはてなブックマークに追加