DevOps 技術: 継続的なテスト

ソフトウェアの品質を高める鍵は、ソフトウェア配信ライフサイクル全体での変更の影響を迅速に把握することです。従来、チームは手動テストとコード インスペクションを使用して、システムの正確性を検証していました。これらの検査とテストは通常、「開発終了」後に独立した段階で行われていました。このアプローチには次のような欠点があります。

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

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

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

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

継続的なテストの実装方法

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

  • テスターが開発と配信のプロセス全体でデベロッパーと連携できるようにします。(以下で説明するのは一般的なパターンですが、「テスター」は役割であり、必ずしもフルタイムの仕事ではありません。)
  • 探索的テスト、ユーザビリティ テスト、受け入れテストなどの手動テスト アクティビティを配信プロセス全体で実施します。

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

  • 単体テスト。通常、単体テストでは 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 個のテストからなるテストスイートよりも価値があります。

継続的なテストを測定する方法

環境の継続的なテストは、次の方法で測定できます。

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

次のステップ