Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

英国政府によるRailsアプリケーションテストの新標準(翻訳)

概要

Open Government Licenceに基づいて翻訳・公開いたします。

日本語タイトルは内容に即したものにしました。GOV.UKのRFCは以下で公開されています。

alphagov/govuk-rfcs - GitHub

英国政府によるRailsアプリケーションテストの新標準(翻訳)

GOV.UKには、アプリに加えた変更をテストするという強靭な文化が根付いています。私たちは多くの場合、変更を加える前に(テスト駆動開発に沿って)テストを書き、変更をデプロイする前に(回帰テストに沿って)既存のテストがすべてパスする必要があります。

GOV.UKアプリの変更に伴うCIテストにパスしたときの画面。

GOV.UKアプリの変更に伴うCIテストにパスしたときの画面。
このアプリには、変更をデプロイする際に実行される追加テストも含まれる。

場合によっては、変更を手動でテストする方が現実的なこともあります。私たちのデプロイプロセスでは、何らかの手動チェックを行うという考え方が長年定着していましたが、手動チェックを増やしすぎると以下のような問題が発生する可能性があります。

  • 将来の変更時にどのようなチェックが必要になるかが見えにくくなる。最悪の場合、どんなチェックを行うべきかという知識が完全に失われてしまう可能性もある。
  • 自動テストと手動チェックのどちらにするかを開発者が思い思いに選択しがちで、両者のバランスが大きく変動して混乱をもたらす可能性がある。

このままでは、GOV.UKが発展を繰り返すに連れて、手動チェックでどの部分をカバーすべきかがわからなくなることが増えてしまうでしょう。自動テストへの置き換えは簡単ではありません。私たちが書くテストは長年にわたって進化を繰り返しており、どの種類のテストにもそれぞれメリットはあるものの、どのテストに投資を継続すべきかという判断は困難です。

これは、今後さらに多くのコンテンツを大規模に配信する準備を進めているGOV.UKにとってエキサイティングな挑戦です。コードが増えればテストも増えるので、品質についてこれまで以上に合意をまとめる必要があります。テストがいつ十分に揃うかという合意は、アプリをCI化するうえでも重要です。本記事では、私たちがこれまでに合意した内容について説明します。

何をテストするか

GOV.UKは70ものアプリケーションやコンポーネントから成り立っているエコシステムであり、そのほとんどがRuby on Railsで書かれています。私たちは、各アプリが単独で動作することをテストで確認しています。

  • 単体テスト、結合テスト、UIテスト: これらはアプリの振る舞いをテストし、他のアプリやサービスとの通信シミュレーションに依存しています。
  • 表示の回帰テスト: レンダリングされたHTMLが期待どおりに表示されることを確認するテストです(ほとんどのアプリは生HTMLではなくコンポーネントを使っています)。
  • 実行時のヘルスチェック: 多くのアプリがデータベース接続などの内部状態をライブで報告する方法を備えています。

アプリをトータルなGOV.UKとして提供するには、アプリ同士の連携が必要です。そのため、個別のテストに加えて、複数アプリにまたがるテストも行います。

すべてのアプリであらゆる種類のテストが網羅されているわけではありません。たとえばコントラクトテストがあるアプリは1つだけですし、JavaScriptの単体テストが存在しないアプリもあります。そうしたテストが本当に足りないのか、実は冗長なのかを見分けるのは困難でした。作業をすすめるには、典型的なGOV.UKアプリのテストがどうあるべきかについて合意をまとめる必要がありました。

新しいテスト標準

テストを増やすだけならいつでもできますが、起こりうる不測の事態は無限にあるので、バランスの落とし所を見出す必要があります。新しいテストを書くときの基準として、いわゆる「テストピラミッド」がよく引き合いに出されます。テストピラミッドは私たちの努力を方向づけるうえでは役に立ちますが、監査ツールとして使うには曖昧な点が多すぎます。私たちに必要なのは、定量化可能で、かつGOV.UKの構成方法に特化したテスト標準だったのです。

ひとつの方法は、セキュリティにおける、いわゆる「攻撃対象領域(attack surface)」の概念を借用することです。人間による攻撃の代わりに「バグによる攻撃」を想定し、コードの特定の部分をテストで防御するというアイデアです。つまり、テストピラミッドの頂点にGOV.UKを配置した巨大な塊を丸ごと相手にするのではなく、発生する可能性のあるバグごとに「サーフェス(surface: 表面)」に小分けして対処するということです。

GOV.UKアプリの「バグサーフェス」図: 金色の円は、アプリのコードベースの変更によりバグが発生する可能性のある場所を示す。

GOV.UKアプリの「バグサーフェス」図:
金色の円は、アプリのコードベースの変更で
バグが発生する可能性のある場所を示す。

バグサーフェスを保護するためのテストは、バグサーフェスごとに種類が異なります。アプリをCIに移行するときの一環として、私たちはテストの種類ごとに「最小限の安全性(safe minimum)はどうあるべきか」について合意をまとめ、その結果新しいテスト標準が生まれました。

バグサーフェスの対象領域 テストの戦略
サーバーサイドのコード 「単体テスト」「結合テスト」「UIテスト」でサーバーサイドのコードの95%以上をカバーすることが要求されます。私たちのアプリのほとんどは既にこれに近い状態を達成していました。CD(継続的デプロイ)を有効にするときの1回限りの目標なので、足りないテストについて再検討するよい機会とみなせます。
APIアダプタ APIとそのアダプタについては、複数のコンシューマーアプリが利用するときにコンシューマー同士の同期が失われる可能性があるため、少なくともコントラクトテストが1つ以上なければなりません。コントラクトテストを1件必須とすることで、今後のテストの追加が十分に促進されるべきです。
クライアントサイドのコード クライアントコードのほとんどは、小さなJavaScriptコードです。しかし徹底的にテストされているアプリがあるかと思えば、まるでテストされていないアプリもあったりと、両極端に偏っていることがわかりました。両者のギャップをシンプルに埋めるために、アプリごとに最低限1つのJavaScriptテストを必須としました。
production環境固有のコード production環境固有のコードには、起動コードや、データベースなどのproductionインフラ環境向けコードなどがあります。各アプリはデプロイ時にヘルスチェックを実行してサービスが運用中であることを証明し、データの読み出しや書き込みに使われる各サービスの死活確認を行う必要があります。
手動タスクおよび定期タスク 対象外。これらのタスクの重要性は当然低いので、自動デプロイに移行した後もバグの影響はさして変わりません。必要であればいつでもテストを増やせます。

これだけでは漠然としていて大して役立ちそうに見えないかもしれませんが、実はその逆です。ここで定めた標準は、どこでテストが必要なのかをねちねちと記述するのが目的ではなく、テストが不足していそうな箇所を発見するためのガイドなのです。うんざりするような要求事項をぎっしり並べるのではなく、既存のテスト文化の延長線上でシンプルに注意を喚起するためのものです。

GOV.UKアプリのバグサーフェスの図: 緑の枠は、さまざまな種類のテストがコードベースのさまざまな領域を保護するのに役立っていることを示す。

GOV.UKアプリのバグサーフェスの図:
緑の枠は、さまざまな種類のテストが
コードベースの領域保護に役立っていることを示す。

新標準を定めるときに、スモークテストとエンドツーエンド(E2E)テストをどうするかが問題になりました。特にE2Eテストは恐ろしく遅く、しかも不安定だったので、これ以上増やすのがためらわれました。

実際のスモークテストは、いわゆる「クリティカルな機能」のテストに追加されたレイヤでしかありません。テストの性質が二次的なものであることを考慮して、現時点では「クリティカルとは何か」の厳密な定義は対象外とすることで合意がまとまりました。今のところ、既存のすべてのスモークテストがクリティカルな機能を表しているという前提で、チェックを2回走らせる価値があるとみなしています。

E2Eテストについてもスモークテストと同様です。残念ながら今のテストは遅くて不安定なので、急ぎの変更で邪魔になる場合は一時的に無効にすることもしょっちゅうです。私たちは、現在のE2Eテストは今後も維持するより削除する方がメリットが大きいということで合意をまとめました。

私たちは、GOV.UKの全アプリを新標準に照らして監査を行いました。複雑な大規模アプリでは問題が増えることもよくありました。比較的楽に修正できる問題もありましたが、さらに調査の必要な問題もありました。新標準がGOV.UKによい影響を与えたかどうかを本当に理解するには、実際に運用を開始する必要があります。

ケーススタディ: Whitehall

GOV.UK最古のアプリであるWhitehallは、運用開始以来多くの重責を担い続けています(ある時期のWhitehallはGOV.UKそのものでした)。テストの新標準を導入するとき、Whitehallをゼロから立ち上げるうえで多くの困難が立ちはだかりました。

Whitehallのテスト新標準との互換性を示すスクリーンショット

Whitehallのテスト新標準との互換性を示すスクリーンショット

最初に、Whitehallのテストカバレッジがどの程度なのかを評価する必要がありました。このときは、手作業による監査のほかにテストカバレッジツールも併用しました。SimpleCovは89%と報告してきましたが、調査したところ、テストが不足している部分は既に使われていないコードであることが判明しました。カバレッジを標準的な値に引き上げるには、そのコードを削除する必要がありました

この監査で最も改善が必要な点が浮かび上がり、それを手がかりに結合テストを追加して、ページを構成する多数のコンポーネントが正常に連携することを確認できるようにしました。ヘルパーやモデルなどの重要なクラスには単体テストを追加しましたが、ロジックの少ない設定用クラスなどにはテストを追加しませんでした。作業後にカバレッジツールを再度実行したところ、95.5%というハイスコアを叩き出しました(目標を上回りました)。

手動で起動するrakeタスクは本来対象外でしたが、その価値があると認められたタスクについてはテストを追加しました。これらのタスクの多くはページのライブ更新などのメンテナンス用途に使われるので、期待どおりに動くことが重要であり、テストで動作を保証するようにしました。これらのテストを追加したことで、カバレッジは96.7%に達しました。

Whitehallはフロントエンドおよび情報公開ツールであると同時に、gov.uk/api/world-locationsなどのAPIエンドポイントの提供も兼ねています。これらのAPIは複数のコンシューマーアプリで使われるので、Pactによるコントラクトテストが必要です。GOV.UKではアプリ間通信にGDS API Adapters gemが使われています。すべてのコンシューマーアプリにテストを追加する代わりに、GDS API Adapters(コンシューマー側)とWhitehall(プロバイダ側)の間にテストを追加しました。

最後の仕上げに、Whitehallがそれに依存するサービスと正常に通信できるようにヘルスチェックをもうひとつ追加しました。既に実装済みのヘルスチェックはRedisとMySQLが対象ですが、追加のヘルスチェックはMemcachedとAWS S3の接続性をテストします。

今後について

テストの新標準は今後すべてのアプリに適用される予定ですが、本記事公開時点で60%以上ものアプリでテストが標準化済みです。テストの新標準を適用したアプリが十分な数に達したら、いよいよ古いE2Eテストの削除を検討できる状態になります。E2Eテストの実行は開発コストを著しく圧迫するうえ、テストによる保護も限定的なものでしかないので、テストの新標準に沿って改善が進めば十分埋め合わられるでしょう。

しかしこれはまだ始まりに過ぎません。絶え間なく進化を繰り返すGOV.UKのために、この新標準を開発者の日常業務にどううまく組み込むかを考える必要があります。今後私たちは、既に合意された内容であっても必要なら異議を唱え、要求事項を増やすべきかを検討しなければなりません。つまり、どんな種類のテストを書くかを深く掘り下げて、足りない部分を埋めるツールやプロセスについて合意をまとめるということです。実用的なE2Eテストとは何か、コードカバレッジの強制は是か非かなど、やることは山積みです。

今後の記事にご期待ください。

GDSでは職員を募集しています

関連記事

2020年のRailsでブラウザテストを「正しく」行う方法(翻訳)

TestProf: Ruby/Railsの遅いテストを診断するgem(翻訳)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。