DevOps 技術: 継続的テスト

ソフトウェアの品質を高める鍵は、ソフトウェア デリバリー ライフサイクル全体にわたる変更の影響を迅速に把握することです。従来は、手動テストとコード インスペクションを使用して、システムの正確性を検証していました。通常、こうしたインスペクションとテストは、「開発完了」後に別のフェーズで行われていました。この手法には、次のデメリットがあります。

  • 手動による回帰テストは実行するのに時間もコストもかかるため、プロセスのボトルネックとなります。ソフトウェアを頻繁にリリースできず、フィードバックを入手するにも時間がかかります。
  • 手動のテストと検査には信頼性がありません。人は手動による回帰テストのような繰り返しの作業を得意としないからです。また、変更が複雑なソフトウェア システムに与える影響を検査によって予測するのは困難であることも信頼性に欠ける理由です。
  • ソフトウェアが「開発完了」になると、開発者は変更についてのフィードバックを受け取るまでしばらく待つ必要があります。これは通常、不具合に優先順位を付け修正する大きな作業になります。パフォーマンス、セキュリティ、信頼性の問題がこの段階で検出されると、多くの場合、対処により大きなコストを要する設計変更が必要になります。
  • また、フィードバック サイクルが長いほど、デベロッパーが品質コードを作成する方法を学びにくくなり、スケジュール上のプレッシャーの中で、開発チームが品質を「他人事」として扱う場合があります。
  • 開発者に自分のコードをテストする責任がなければ、テストが容易なコードの作成方法を習得するのは困難です。
  • 時間が経つにつれて変更が加えられていくシステムの場合、テスト ドキュメントを最新の状態に維持するには、無視できない量の作業が必要になります。

代わりに、チームは次のことを行う必要があります。

  • ソフトウェア デリバリー ライフサイクル全体にわたって、全種類のテストを継続的に実施します。
  • 継続的デリバリー パイプラインの一部として実行される、高速で信頼性の高い一連の自動テストを作成して取りまとめます。

DORA の調査では、チームは高品質のソフトウェアをより迅速に構築(および構築する方法)するだけでなく、ソフトウェアの安定性の向上、チームの心身の疲労の軽減、デプロイの問題解決の負担も軽減されています。

継続的テストの実装方法

ソフトウェアの品質を高めるには、デリバリー プロセス全体で自動テストと手動テストを継続的に実行し、開発中のシステムの機能とアーキテクチャを検証する必要があります。この規範には、組織的な要素と技術的な要素の両方が含まれます。DORA による調査の結果、チームは次の作業を行うと、より優れた成果を上げることがわかっています。

  • テスターがソフトウェア開発とデリバリーのプロセス全体でデベロッパーと連携できるようにします(以下では一般的な例を説明しますが、「テスター」は専業である必要はなく 1 つの役割です)。
  • 探索的テスト、ユーザビリティ テスト、受け入れテストなどの手動テスト アクティビティを配信プロセス全体で実施します。

重要な技術アクティビティには、以下を含む一連の自動テストスイートの構築、維持があります。

  • 単体テスト。通常、単体テストでは 1 つのメソッド、クラス、または関数を単独でテストして、デベロッパーに対し、作成したコードが意図どおりに機能することを保証します。テスト可能で保守しやすいコードにするために、コードを作成する前に単体テストを作成します。これは、テスト駆動型開発(TDD)と呼ばれる手法です。
  • 承認テスト: 通常、実行中のアプリまたはサービス(通常は依存関係はテストダブルに置き換えられます)をテストし、上位レベルの機能が設計通りに機能すること、回帰エラーが発生していないことを保証します。受け入れテストのサンプルで、ユーザー ストーリーに対するビジネス承認条件や API の正確性を確認できます。こうしたテストは、開発プロセスの一環として作成します。自動承認テストに合格するまでは、成果物を「開発完了」として宣言することはできません。

次の図(当初、Brian Marick により作成され、のちに『Agile Testing: A Practical Guide for Testers and Agile Teams』という本の中で引用されています)は、実行する自動テストと手動テストのタイプを示しています。

画像

上図で強調表示されている自動テストは、継続的デリバリーデプロイ パイプランに組み込まれます。このようなパイプラインでは、すべての変更でビルドを実行してソフトウェア パッケージを作成し、単体テストを実行します。また、場合によっては静的解析などの他のチェックが行われることもあります。これらのパッケージが最初のステージに合格すると、より包括的に自動化された承認テストと、たいていパフォーマンス テストや脆弱性スキャンなどの非機能的なテストの一部は、自動的にデプロイされたソフトウェアで実行されます。ビルドが承認テストに合格すると、通常、手動での探索的テストとユーザビリティ テストに使用できるようになります。最後に、こうした手動の手順でエラーが 1 つも見つからなければ、アプリはリリース可能とみなされます。

パイプラインの一部として継続的にテストを行うと、開発者への迅速なフィードバック、チェックインからリリースまでのリードタイムの短縮、本番環境でのエラー率の低下につながります。開発者は、成果物の大半を数日や数週間ではなく数分で検証してもらえるため、バグをすぐに修正できるようになります。

次の図は、単純な線形デプロイ パイプラインの例を示しています。この例では、緑色は問題が検出されなかったということを意味し、赤色は 1 つ以上の問題が検出されたことを示しています。

画像

デプロイ パイプラインのパターンでは、すべての変更によってリリース候補が作成されます。そしてすばやいフィードバック ループによって、プロセスのできるだけ早い段階で問題を捕捉できます。パイプラインの最後に到達したパッケージでも、チームがそれをリリースするのに不安を感じる場合、あるいは本番環境で欠陥が見つかった場合は、テストを追加または更新してパイプラインを改善する必要があります。

主な注意点

  • テストにデベロッパーを関与させること。DORA の調査では、開発者が一連の自動テストの作成と保守を主に担当し、開発者が承認テストの失敗を簡単に修正できる場合に、パフォーマンスが向上しています。他のグループがテスト自動化を所有していると、多くの場合、次の 2 つの問題が生じます。

    • 頻繁にテストスイートが壊れた状態になる。コードを変更すると、テストの更新が必要になることがあります。デベロッパーがテスト自動化を担当していなければ、担当のチームがテストを修正するまで、ビルド パイプラインが壊れた状態になります。
    • デベロッパーが、テストしにくいコードを生成している。デベロッパーが、与えられた問題をコードのテスト方法を考慮せずに解決しがちになります。その結果、コードの設計が不十分で、費用とメンテナンスの手間がかかるテストスイートになる可能性があります。

    テスターと QA チームは、このような作業で重要な役割を果たします。テスト担当者はユーザーがどのようにシステムを操作するかを把握しているため、システムに対して独自の視点を持っています。チームが物理的に離れた場所にいる場合でも、テスターと開発者がペアになり、画面共有ツールを使用して一連の自動テストを作成し発展させることをおすすめします。この方法より、お互いから学び、リアルタイムで問題を解決できます。また、テスターは、探索的テストとユーザビリティ テストの実施に加え、一連のテストの取りまとめをサポートするうえでも不可欠な役割を担います。

  • テストスイートをキュレートすること。テストスイートを継続的に見直して、不具合の発見と複雑性とコストの管理に努めてください。例:

    • 通常、承認テストスイートは、自動承認基準の集合ではなく、システムでの実際のエンドツーエンドのユーザー操作全体を表すものでなければなりません。プロダクトが進化するにつれ、こうしたシナリオも、テストスイートで検証されるようになります。このプロセスの詳細については、Angie Jones によるテスト自動化を成功させる基盤の設定の動画をご覧ください。
    • コードを変更するたびに複数の単体テストも変更しなければならない場合、モックに頼りすぎているか、単体テストスイートの無駄を取り除けていないことが考えられます。
    • テストスイートをうまく分解できる状態にします。UI に変更を加えると、必ず複数の承認テストが失敗するとしたら、ページ オブジェクト パターンを使用して、テストをテスト対象のシステムから切り離してください。
    • テストの維持に多くの費用がかかる場合、ソフトウェアのアーキテクチャに問題がある可能性があります。チームの日々の作業にリファクタリングを組み込むなど、ソフトウェアのテストを容易にするための投資を続けます。
  • 単体テストと承認テストを誤った比率で使用しないこと。自動テストスイートに固有の設計目標は、できるだけ早くエラーを見つられるようにすることです。この理由から、実行に時間のかかる承認テストよりも前に、すばやく実行できる単体テストを実行します。さらに、この両方のテストを手動テストの前に実行します。

    最も速いテストのカテゴリでエラーを見つける必要があります。承認テストまたは探索的テストでエラーを見つけた場合、次回はそのエラーをよりすばやく、より低コストで捕捉できるようにする単体テストを追加します。Mike Cohn は、次の図に示されているテスト自動化ピラミッドが理想的だと説明しています。このピラミッドでは、単体テストによってエラーのほとんどを捕捉します。

    画像

  • 信頼性の低いテストの容認。テストは信頼できる必要があります。つまり、テストに合格したら、ソフトウェアが信頼できることを保証し、テストの失敗は実際の欠陥を示す必要があります。特に、不安定なテストを容認してはいけません。Google での不安定なテストの削減策をご覧ください

継続的テストの改善方法

組織の中でデベロッパーによる単体テストが確立されていなくても、心配はいりません。単体テストは、Google の初期の頃は広く行われていませんでした。現在の包括的な単体テストは、Google のボランティア グループ「Testing Grouplet」によって普及されました。単体テストの知識を Google 全体に広め、その重要性をデベロッパーに周知することに焦点を当てた実践のコミュニティを構築することで、単体テストの導入を推進してきた彼らの功績をお読みください

テストを十分に自動化していない場合、まずはスケルトン デプロイ パイプラインの構築に取り掛かってください。たとえば、単体テストと承認テストをそれぞれ 1 つ作成し、探索的テスト環境を立ち上げる自動デプロイ スクリプトを作成して、テストとスクリプトをつなぎ合わせます。その後は、プロダクトまたはサービスの進化に併せて徐々にテスト カバレッジを増やし、デプロイ パイプラインを拡張します。

すでに既存のシステムに取り組んでいる場合、この記事のガイダンスに従うとしても、包括的な自動テストスイートの改良を続けてください。代わりに、価値の高い機能を対象とした少数の承認テストを作成します。その上で、新しい機能を作成する場合でも、機能を変更する場合でも、必ずその機能を対象とした単体テストと承認テストを作成するようにデベロッパーに要請します。メインのコードとテストコードの両方の品質と保守しやすさを改善するために、TDD の採用を検討してください。最後に、承認テストが壊れた場合は、将来その欠陥をすぐに見つけることを目的とした単体テストを作成します。

保守にコストがかかり、信頼できないテストスイートがある場合、恐れずにそのテストスイートを取り除いてください。確実で実行時間が短く、信頼できる 10 個のテストからなるテストスイートのほうが、保守しにくく、誰も信頼していない 100 個のテストからなるテストスイートよりも価値があります。

継続的テストの測定方法

ご利用の環境における継続的テストの結果は、次のように測定できます。

テスト要因 測定データ 目標
承認テストと単体テストの作成者 デベロッパー、テスト担当者、会社内のその他のグループが作成したテストの割合 デベロッパーを承認テストのメインの作成者と保守担当者にする。
受け入れテスト、探索的テスト、本番環境で検出されたバグの数 一定の期間にわたる、検出されたバグの比率の変化 「低コスト」のテストフェーズでより多くのバグが検出される。チームにより探索的テストと本番環境で検出されたバグの自動テストが追加され、承認テストで検出されたバグを検出するための単体テストを追加する。
承認テストの失敗を修正するためにかかった時間 一定の期間にわたる、テストの失敗を修正するためにかかった時間の変化(短縮されていなければなりません) デベロッパーが承認テストの失敗を簡単に修正できるようになる。
自動テストの有意性 実際の欠陥を表す自動テストの失敗の数量と、適切にコーディングされていなかった自動テストの数量を追跡する テストの失敗が、常にプロダクトの実際の欠陥を示すようにする。
デリバリー パイプラインでの自動テストの実行 パイプライン トリガーで常にすべてのテストスイートが実行されるかどうか確認する(はい / いいえ) メインのパイプラインとワークフローの一環として自動テストが実行されるようにする。

次のステップ