t0mmy

2020年12月30日に参加

学習履歴詳細

単体テストの考え方/使い方 4章 読了

やったこと

  • 単体テストの考え方/使い方 4章 読了

学んだこと

学び

  • 退行保護に最大限備えるためには、テストの際にできるだけ多くのプロダクションコードを実行すること
  • テストコードとプロダクションコードが密結合になっていると、false positive が発生しやすい
    • false positiveの常態化は、テストが機能しなくなる原因となる、危険な状態
  • 「退行保護」「リファクタリング耐性」「迅速なフィードバック」の三つは、トレードオフの関係
    • 例) 「退行保護」「リファクタリング耐性」を最大限満たすと、速度が遅くなり、「迅速なフィードバック」は実現できない(E2Eテストなど)
  • プロダクションコードの「what」ではなく「how」に目を向けているテストケースは、壊れやすい
  • E2Eで検証するのは「アプリケーションにとって最も重要な機能、かつ、統合テストや単体テストで十分に検証できないテスト」のため
    • 統合テストや単体テストで十分検証可能なテスト項目は、E2Eで検証する必要なし
  • テストは、基本ブラックボックステストとして書く
    • ブラックボックステストは、プロダクションコードに依存しないため、リファクタリングで壊れにくい(≒リファクタリングに耐性がある)ため
    • ブラックボックステストで網羅出来ず、検証が必要な部分に限って、ホワイトボックステストを書く

気付き

  • テストアラートの話は、運用やセキュリティに通ずるものがある
    • 過剰なアラート(誤検知含む)は、オペレーターの注意を削ぐ
    • 見逃しは、あってはならない
  • プロダクションコードを呼び出す側の視点(つまりブラックボックステスト)でテストを書くと良い
    • ホワイトボックス的なテストは、実装の詳細に強く依存するため、リファクタリングで破壊されやすい
  • 「コンパイルエラーを伴わない false positiveは修正が困難」とは、言い換えると、コンパイルエラーや文法エラーを伴うテスト失敗は、修正しやすい
    • => テストの失敗を、コンパイルエラーや文法エラーで検出できるようなテストは、壊れても修正しやすいテスト
    • つまり、テストは大きく三種類に分かれる
    • 壊れにくいテスト(≒リファクタリング程度では壊れないテスト)
    • 壊れやすいけど、修正しやすいテスト(問題個所を、コンパイルエラーや文法エラーで検出できる)
    • 壊れやすく、修正しにくいテスト(動きはするし、値も返すが、assert でコケるテスト。バグなのか、実装なのか区別が困難)

メモ

この章で扱う事

  • 良い単体テストを構成する性質の大きな分類
  • 理想的なテストについての定義
  • テスト・ピラミッドについて
  • ブラックボックステストとホワイトボックステストの使い方

単体テスト 4つの柱

  • 柱1 たくさんバグを検出できること(退行保護)

    • 特に、ドメインロジックは、たくさんバグを見つけたい
    • 反対に、UIやgetter/setter部分は、動くことの確認程度に抑える
    • 必要なら、外部依存部分も含めて、想定通りに動くことをテストする
    • 退行保護に最大限備えるためには、テストの際にできるだけ多くのプロダクションコードを実行すること
  • 柱2 プロダクションコードのリファクタリングによって、テストが簡単には壊れないこと

    • テストコードとプロダクションコードが密結合だと、リファクタリングによってテストコードが壊れやすい
    • テストコードが実装に追いついていない(言い換えると、テストコードに問題がある)この状態を、書籍では false positive と呼んでいる
    • false positive は、以下に示す単体テストの利点を潰してしまう
    • テストを実行することで、プロダクションコードに埋め込まれた問題に気付くことが出来る
      • false positive によるテスト失敗が常態化してしまい、プロダクションコードのミスに気付けなくなる
    • テストを実行することで、「プロダクションコードが退行していないこと」を確認できる
      • false positive によるテスト失敗が常態化してしまい、誰もテストを信用しなくなる
      • 最悪、退行を防ぐ手段として「可能な限りコードを変更しないこと」という戦略が採択される
    • 特に、コンパイルエラーを伴わない false positive は、バグとの区別が困難であり、調査に多くの労力が必要
  • 柱3 迅速なフィードバック

    • テストが短時間で完了できると、開発者は頻繁にテストを実施し、結果としてプロダクションコードのバグを早期に発見できる
  • 柱4 保守しやすさ

    • テストにて、何を検証しているのか把握しやすいこと
    • テストの実施(実装できるまで準備する)容易さ

テストピラミッドとは

  • テストピラミッドにて E2E が最上位に位置する(≒最もテストケースが少ない)とされる理由
    • E2Eで検証するのは「アプリケーションにとって最も重要な機能、かつ、統合テストや単体テストで十分に検証できないテスト」のため
    • E2Eにこそ、不要なテストケースを持ち込まないようにしたい

ブラックボックステストとホワイトボックステスト

  • ブラックボックステストはinとout を、ホワイトボックステストは、プロダクションコードの詳細を検証する
    • ホワイトボックステストは、プロダクションコードに強く依存するため、リファクタリングによって壊れやすい
    • 基本的に、テストはブラックボックステストとして書くことになる
    • ブラックボックステストで網羅できない部分を、例外的にホワイトボックステストとして書く ... という運用になる

まとめ

良い単体テストを構成する柱は、以下の4つ。

  1. 退行(regression、つまりバグ)に対する保護: たくさんバグを検出できるか
    • テストにより、どれだけ多くのバグを検出できるか
    • 「退行に対して保護されている」状態とは、テストによってより多くのバグを検出できる状態を示す
  2. リファクタリングへの耐性: リファクタリングした時に、テストが壊れにくいか
    • false positive を押さえつつ、プロダクションコードをリファクタリングできるかを示す性質
    • false positive : プロダクションコードは正しいのに、失敗してしまうテスト - テスト失敗に慣れてしまい、テストの失敗に注意を払わなくなる - テストへの信頼が失われる
    • 「リファクタリングへの耐性が高い」状態とは、バグのみを、バグとして警告するような状態を示す
  3. 迅速なフィードバック
    • テストが完了する速度
  4. 保守容易性
    • テストにて、何を検証しているのかの把握しやすさ
    • テストの実施(実装)容易さ
  5. 「退行保護」「リファクタリングへの耐性」「迅速なフィードバック」は、トレードオフの関係
    • 最大限に備えることが出来るのは、二つまで
    • テストが増えるほど、遅くなるよね?
  • テストケースの作成にはブラックボックステストを、分析にはホワイトボックステストを用いる
    • ブラックボックステストにより、実装の詳細に依存しなくなる
テスト

2023年03月20日(月)

2.0時間