リグレッションテスト(回帰テスト)は、システム全体のテストであり、システムのある部分の小さな変更がシステムの既存の機能を損傷していないことを保証する目的で実行されます。リグレッションテストは意図した修正をシステムに反映した際に、解決するよりも多くの問題を引き起こしていないかを確認するための重要なテストです。

リグレッションテストを実行しない場合に起こりうるケースを分かりやすく説明するために、架空のストーリーを例に解説します。

何が影響したのかがわからない?

ある日、アクメウィジェット社(※架空の会社)の経理部門のマネージャーが、会社の財務システムにバグを発見しました。それは、期限切れ請求書をレポートするモジュールが、期限切れ請求書をすべてリストアップしていないことが判明したのです。バグを説明するJIRAチケットが作成され、問題の再現方法が説明されました。このバグはとある開発者に割り当てられ、修正が行われました。

開発者は会社の方針に従い、新しいコードのユニットテスト(単体テスト)を行いました。ユニットテストでは、修正が意図したとおりに動作することが疑う余地もなく証明されました。(図1参照)

A screenshot showing that typically the scope of retesting code is at the unit test level.図1:通常、コードの再テスト範囲はユニットテストレベルで実行される

開発者が JIRA でバグが修正されたことを報告すると、QAチームは合格したユニットテストを見て、開発者が会社のコードカバレッジポリシーに従っているかどうかを確認しました。また、QAテスト担当者は、新しいコードがインストールされたテストシステムを演習し、その修正が期待通りに動作することを確認しました。テストコードは、テストシステム上で期待通りに動作しました。

そして、その修正版を本番にリリースしました。ここまでは順調でした。

一週間が過ぎました。そして、経理部が会社の月末の処理を実行しようとすると、奇妙な動作が起こります。Aging Reportを発行しようとすると、タイムアウトしてしまうのです。(Aging Reportとは、請求書の金額を、現在、30日経過、60日経過、90日経過、90日以上というように、経過日数で区切り、集計したもの。)

アクメウィジェット社でパニックが起こります。月末の損益計算書がないと、利益が出ているのか損をしているのか分かりません!経理部も慌てています。「前月はうまくいっていたのに、今月になって壊れてしまった。」経理部長はソフトウェア開発マネージャに連絡して、この問題を報告し、できるだけ早く改善するように求めました。

ソフトウェア開発マネージャは、月末の損益計算を実行する前のコード変更を示すチケットを見つけるために JIRA を調べます。期限切れの請求書問題に対処するための JIRA チケットが、彼を見つめています。ソフトウェア開発マネージャーは技術リーダーを呼び、一緒にコードとユニットテストを確認します。すべてがうまくいっているように見えます。次に、この問題を別の視点から見るために、QAマネージャーを呼びます。QAマネージャーにも表面上はすべてうまくいっているように見えます。

そこで、QAマネージャーは直感します。彼女はユニットテストを見て、そのテストが、その年の第1四半期の請求書のデータを含む小さなテストデータベースに対して実行されていることに気づきました。そのデータは、エラーを再現するのに十分であったため、バグを修正し、ユニットテストを成功させることができました。しかし、このコードは本番データを使ってテストされたことはありませんでした。

技術責任者は、その修正を行った開発者に連絡を取ります。二人は一緒に修正内容を確認し、小規模なデータセットに適用した場合は問題がないことを発見します。技術責任者は、そのコードを本番環境のデータセットに対して実行して見ました。その結果、新しいコードはgetPastDueInvoices(dueDate)という関数でカプセル化されており、本番データに対して実行すると5秒かかることが判明しました。

このコードの修正は、ユニットテストでは実行に1.5秒しかかかりませんでした。そのため問題がないように思われましたが、本番ではそうではありませんでした。会計システムは、Invoiceモジュールへの呼び出しに対して2秒のタイムアウト期間を設定していました。(図2参照)

Figure 2-Regression Tests

図2:リグレッションテストは、システムの一部で新しいコードがシステム全体に好ましくない副作用を引き起こさないことを保証する。


開発者はコードの修正をユニットテストでのみ、再テストしていたことが判明しました。そして、QAチームはハイレベルな検証を行ってはいましたが、リグレッションテストは行われていませんでした。この修正は、ユニットテストでは期待通りに動作していたのに、本番ではシステムを壊してしまったのです。もし、その修正が本番稼動しているデータのコピーを使用したシステム全体のリグレッションテストに組み込まれていたならば、本番稼動する前に問題が発見された可能性は非常に高いでしょう。このように、リグレッションテストの価値と重要性は非常に高いものなのです。

リグレッションテストは再テスト以上のもの

リグレッションテストは重要です。悲しいことに、ある会社はリグレッションテストをしていると思い込んでいて、実際は再テストをしているに過ぎないことがあります。再テストは、特定のコード変更が期待通りに動作することを確認することです。リグレッションテストは、変更が導入された後、システム全体が期待通りに動作することを確認することです。このように、リグレッションテストの設計と実装は、再テストよりもはるかに広い活動範囲を持っています。

一般的に、再テストは、コードが作成されているとき、または、そのごく近くで、迅速に行われます。リグレッションテストは、テストの実行に必要な長い時間をかけられる、より多くの時間があるときに、開発ライフサイクル(SDLC) の上位段階で実施されます。つまり、いくつかの再テストは非常に複雑で時間がかかりますが、包括的なリグレッションテストを実行するために必要な時間の長さに比べたら、全くレベルが違います。適切なリグレッションテストでは、システムのすべての側面がテストされ、監視されなければならないことを忘れないでください。適切なシステム全体のモニタリングが行われないままリグレッションテストを実施すると、テスト作業が推測ゲームに変わってしまいます。冒頭のシナリオで示したように、エラーはシステムのある部分で発生し、別の部分の動作が原因であることがあります。適切なモニタリングは、問題や根本原因を特定するために必要なシステムに対する洞察を与えてくれます。

イテレーションにリグレッションテストを組み入れるには?

リグレッションテストの必要性は強く説かれています。しかし、アジャイルでリグレッションテストを実施するのは難しいかもしれません。アジャイルとDevOpsの目標は、短い、速いリリースサイクルで、できるだけ早くユーザーの手に作業ソフトウェアを届けることです。しかし、リグレッションテストには時間がかかります。おそらく、1回のイテレーションで可能な時間よりもずっと長い時間がかかるでしょう。では、どうすればいいのでしょうか?

解決策の1つは、イテレーション間でリグレッションテストのタイミングをずらすことです。下の図3は、3つのイテレーションのタイムラインを示しています。各イテレーションでコードのバージョンがリリースされます。しかし、イテレーション中に作成されたコードのリグレッションテストは、イテレーションの半分から始まり、次のイテレーションまで継続されます。イテレーションの途中からリグレッションテストを開始することで、テスト担当者は、イテレーション中に新しいコードが「定着」したときに問題を発見することができます。そして、次のイテレーションで修正を実装し、吸収することができます。

Figure 3 - Staggering Regression Tests

図3:リグレッションテストを繰り返し行うことで、アジャイル開発方式をサポートしつつ、リグレッションテストに十分な時間を確保することができます。

イテレーションで開発中のコードの最新バージョンだけにリグレッションテストを限定すると、ウォーターフォール的なダイナミズムを生み出す危険性があります。開発チームは、修正を行う前にリグレッションテストが完了するのを待って足踏み状態になる可能性があります。そして、いったん問題が発見され、開発者によって修正されると、リグレッションをテストする担当者は、それ以上のアクションを起こす前に、新しいコードが利用可能になるまで待つ必要があります。明らかに、この「引き継ぎのバトンパス待ち」のパターンは、ソフトウェア開発に対するアジャイルアプローチと相反するものです。リグレッションテストを繰り返し行うことで、テスト担当者は必要なテスト範囲を実行するために必要な時間を確保し、開発担当者はその間に新しいコードを作成することができるようになります。

すべてを統合する

最初のリリースでコードが完璧であることは稀です。現代のソフトウェア開発では、ソフトウェアをリリースすることは、最初から正しく作ることよりも、時間をかけてより良いものにしていくことが重要であると認識されるようになりました。

これは、企業がただコードをドアから押し出して、リリースの品質を偶然に任せていると言っているのではありません。むしろその逆です。先進的な企業は、ソフトウェア開発ライフサイクルのすべての段階において、テストを習慣として実施するよう多大な努力をしています。また、先進的な企業ほどシステムが大きくなり、ソフトウェアの開発速度が上がれば上がるほど、副作用が発生する可能性が高くなることを理解しています。そのため、ソフトウェア開発ライフサイクルを通じて包括的なテストを行う企業は、リグレッションテストに特に重点を置いています。リグレッションテストは、リスク軽減のための最初で最良の防御線であり、ソフトウェアの一部を構成するコードが本当にシステム全体をより良くするのかどうかを確認します。

mablは、チームがアプリケーションの自動テストを作成し、リグレッションテストを自動化するのを支援します。mablは、マシンラーニングを用いてテストレポートを分析し、ソフトウェア品質および、視覚的な変化、パフォーマンスを監視します。mablは14日間無料でお試し利用頂けます。