Open6

テスト関連のアウトプット

いなかいなか

カバレッジ

命令網羅(statement coverage)(C0)

それぞれの命令が少なくとも1回は実行されるようにテスト設計する。

分岐網羅(branch coverage)(C1)

それぞれの判定条件における真偽が少なくとも1回は実行されるようにテスト設計する。
C1カバレッジが100の場合、必然的にC0カバレッジも100%になる。

条件網羅(condition coverage)(C2)

それぞれの条件文における真偽が少なくとも1回は実行されるようにテスト設計する。
C2カバレッジが100%であっても、C0カバレッジ、C1カバレッジが100%になるとは限らない 。

複合条件網羅(multiple condition coverage)(MCC)

それぞれの条件における真偽の組み合わせが全て実行されるようにテスト設計する。
C1とC2どちらも満たすものになる。

カバレッジを計測する目的は、「テストケースが十分に網羅されていない」コードを限りなく少なくすること。
ただ、バグを適切に検出できるテストケースを作ることが大切。
目標値を100%に設定することは避ける。Googleでは60% を「許容範囲」、75% を「推奨範囲」、90% を「模範的」としているらしい。
https://testing.googleblog.com/2020/08/code-coverage-best-practices.html

いなかいなか

ブラックボックステスト

内部構造や動作を覗き見することなく、アプリケーションの機能を調べるソフトウェアテストの手法のこと。アプリケーションを見えない箱として扱い、入力と結果の整合性を確認する。

テスト対象の振る舞いをテストする。内部構造に注目していないので、リファクタリングしてもテストが壊れにくい。

同値分割法

同じ結果となる入力値を同値クラスという部分集合に分割し、その同値クラスの値を等価とみなす。その中から代表の値を1つ選んでテストケースを作る技法。
同値分割法だけでは十分なテストケースを作成できないので、次の境界値分析と合わせてテストケースを作成する。

境界値分析

「◯◯以上」や「◯◯未満」などの値の境界となるところをテストする技法。

いなかいなか

単体テストの3つの手法

  • 出力値ベーステスト
    • テスト対象のコードが返す値だけを検証する
    • テスト対象のコードが何も副作用を生み出さず、呼び出し元に返す戻り値しか処理の結果がないことが前提となる
  • 状態ベーステスト
    • 検証する処理の実行が終わった後にテストの対象の状態を検証する
    • 状態とは、テスト対象システムや協力者オブジェクト、データベースやファイルシステムなどのプロセス外依存の状態を指す
  • コミュニケーションベーステスト
    • モックを用いてテスト対象システムとその協力オブジェクトとの間で行われるコミュニケーションを検証する
いなかいなか

単体テストで重視したいこと

リファクタリング耐性

  • 関数の「実装」にではなく「振る舞い」に対してテストする
  • モックはできるだけ使用しない
    • 実装内部で呼び出す関数に依存し、テストが脆くなる
    • DBをモックするとクエリ側に含まれたビジネスロジックが検証できず偽陰性が発生しうる
      • クエリからビジネスロジックを完全に取り除くのは難しい
    • モックを使用するケース
      • アプリケーションの管理下になりプロセス外依存
        • 外部サービスの提供するAPI
        • フロントエンドから見たAPI
      • DBはバックエンド目線で言えば管理下にあるプロセス外依存と言えるので、モックすべきではない

スコープ対象内の信頼性

  • 異常系テストをたくさん書く
    • 統合テストでは異常系を書きづらいので単体テストでできるだけカバーする
  • 偽陽性を防ぐ
    • 偽陽性のテスト失敗が多いと、テスト結果が信頼されなくなり、重要なバグを見落とす
  • テスト対象スコープが限られていることから偽陰性を防ぐのは難しい
    • より上位の信頼性担保は統合テストの役割

テスト自体の保守性

  • テストコードにロジックを含めない
  • 保守性の理想は「機能要件が変わらない限り二度と変更の必要がないテスト」
  • 失敗時のエラーメッセージを明確にする
  • テストする挙動に合わせて命名する
    • 日本人のチームであれば日本語でいいかも

実行容易性

  • ローカルでもコマンド1つで簡単に実行できる
  • CIで自動実行される
いなかいなか

統合テストで重視したいこと

リファクタリング耐性

  • インターフェイスを保っていれば内部は自由にリファクタリングが可能になる
  • 単体テストよりもリファクタリング耐性が大きく高まる

単体テストでカバーできない範囲の信頼性

  • フレームワークが実行するミドルウェア
  • DBやクエリの実行
  • 最終的なレスポンスの形式
  • 統合テストでも「設定」の変更をテストできない場合も多い

保守性

  • テスト実行環境、テストデータを用意などで単体テストよりも仕組みが複雑になるので保守性が下がる
  • テストケースが増えるほどデータを用意するためのコードが増え、保守に苦労する
いなかいなか

Sinon.js

テストダブル

HTTPリクエストをテストダブルに置き換えることで、「リクエストが成功しレスポンスが返却される」「リクエストが失敗しエラーステータスが返却される」などの状況を作ることができる。
実際の通信エラーなどに左右されず、テストダブルから受け取った情報をもとにサービスがどのような挙動をするのかを検証すれば良い。

テストスタブ

テスト対象に「間接的な入力」を提供するために使う。

テストスパイ

テスト対象からの「間接的な出力」を検証するために使う。出力を記録しておくことで、テストコードの実行後に値を取り出して検証できる。

モックオブジェクト

テスト対象からの「間接的な出力」を検証するために使う。テストコードの実行前に、あらかじめ期待する結果を設定しておく。

onSecondCall