ブラックボックステストは特定の入力に対して正しい出力が返されるかを判定するユーザ視点のテスト。
仕様を満たしているかどうかがテスト観点になる。
内部構造を考慮しないため、たまたま正しい出力が返されたのか否かは判定できず、潜在的なバグを見つけられない。

同値分割

同等の結果が返される入力値の集合を同値クラスと呼ぶ。
つまり、ある値で欠陥が検出されるとき、同じ同値クラスの他の値でも同じ欠陥が検出される。
逆も同様で、ある値で欠陥が検出されないとき、同じ同値クラスの他の値でも検出されない。

同値クラスを洗い出し、各同値クラスから1つの値のみをテストすることでテストケース数を減らせる。

たとえば特定の範囲が有効な入力のとき、その範囲が有効な同値クラス、その範囲よりも上と下がそれぞれ無効な同値クラスであり、合計で3つの同値クラスがある。

境界値分析

同値クラスの範囲の境界でテストすることを境界値分析と呼ぶ。
欠陥は境界値で発生することが多いため、効率的に検出できる。

組み合わせテスト

条件の組み合わせに対する結果をテストすることを組み合わせテストと呼ぶ。
組み合わせテストには有則のものと無則のものがある。

  • 有則
    • 条件の組み合わせごとに結果が仕様として決まっているもの
    • 仕様通りに実装されているかを評価するためにテストする
    • 仕様として決まっている範囲なので組み合わせが膨大な数になりにくい
    • デシジョンテーブルを使う
  • 無則
    • 有則でないもの
    • 特定の組み合わせで意図しない不具合が発生しないかを検出するためにテストする
    • 仕様として決まっていないので組み合わせが膨大な数になりやすい
    • すべての組み合わせをテストすることはできないので、2つや3つの条件の組み合わせだけを網羅することが多い
    • 直交表やペアワイズ法などを使う
      • ペアワイズ法による有名なテストケース作成ツールとして、Microsoftが作成した PICT がある

デシジョンテーブル

条件の組み合わせに対する結果をまとめた表をデシジョンテーブルと呼ぶ。

  1. ある処理におけるすべての条件を縦に並べる
  2. その下にすべての結果を縦に並べる
    • 条件と結果は区別できるようにする
  3. 条件の組み合わせの数だけルールを横に並べる
  4. 条件の組み合わせを埋める
  5. 列ごとに結果を埋める

1234
年齢8歳以上YYNN
身長130cm以上YNYN
ジェットコースター乗車可能x
ジェットコースター乗車不可能xxx

特定の条件のみで結果が決まる場合、それ以外の条件を省略することでルール数を削減できる。
省略された条件は - などを記入するとわかりやすい。

123
年齢8歳以上YN-
身長130cm以上Y-N
ジェットコースター乗車可能x
ジェットコースター乗車不可能xx

矛盾している条件がある場合、結果には N/A (Not Applicable) と記載する。

1234
年齢18歳以下YYNN
年齢65歳以上YNYN
割引ありN/Axx
割引なしN/Ax

条件が3値以上ある場合、各欄に直接値を記入することでルール数を削減できる。

12345678910111213141516
ゴールド会員YYYYYYYYNNNNNNNN
シルバー会員YYYYNNNNYYYYNNNN
購入金額10000円以上YYNNYYNNYYNNYYNN
購入金額5000円未満YNYNYNYNYNYNYNYN
10%割引N/AN/AN/AN/AN/AxN/AN/A
5%割引N/AN/AN/AN/AN/AxN/AxN/A
3%割引N/AN/AN/AN/AN/AxN/AxN/A
割引なしN/AN/AN/AN/AN/AN/AxN/Axxx

123456789
会員種別ゴールドゴールドゴールドシルバーシルバーシルバー非会員非会員非会員
購入金額 (p)p >= 100005000 <= p < 10000p < 5000p >= 100005000 <= p < 10000p < 5000p >= 100005000 <= p < 10000p < 5000
10%割引x
5%割引xx
3%割引xx
割引なしxxxx

1234567
会員種別ゴールドゴールドゴールドシルバーシルバーシルバー非会員
購入金額 (p)p >= 100005000 <= p < 10000p < 5000p >= 100005000 <= p < 10000p < 5000-
10%割引x
5%割引xx
3%割引xx
割引なしxx

パラメタライズドテスト

パラメータ化テストとも呼ばれる。テスト設計ではなくテスト実装の技法。
テストコードとテストデータを分離し、テストデータをパラメータとして渡すことで、複数の入力値と期待値の組によるテストを共通化する。
また、仕様変更などで結果が変わったり、テストケースを増減させたりしたときに修正しやすくなる。

プロパティベーステスト

テスト対象が取りうる任意の入力に対して、出力が満たす性質(プロパティ)を検証するテスト。
一般的にテストと言った際に指す、特定の入力に対して特定の出力になることを検証するテストは、事例ベーステスト、実例ベーステスト、Exampleベーステストなどと呼ばれる。

たとえば整数xとyの和を計算する関数 add(x, y) のテストを行うとする。

事例ベーステストでは以下のように入出力の組ごとにテストする

  • xとyが1と2のとき、出力が3
  • xとyが3と5のとき、出力が8
  • etc

プロパティベーステストでは入力に任意の整数をランダムかつ大量に渡して、以下のようにテストする。

  • add(x, y)add(y, x) と等しい
    • 可換則
  • add(x, add(y, z))add(add(x, y), z) と等しい
    • 結合則

また、配列を昇順にソートする関数のプロパティベーステストは以下のようになる。

  • 配列の長さが変わらないこと
  • 配列に含まれる要素が変わらないこと
  • 配列の先頭が配列内の最小値になっていること
  • 配列の末尾が配列内の最大値になっていること

よく使われるプロパティの例は以下の通り。

  • 逆の操作をすると元に戻ること
    • エンコード/デコード
      • x == decode(encode(x))
    • シリアライズ/デシリアライズ
      • x == deserialize(serialize(x))
    • 配列のreverse
      • arr == arr.reversed().reversed()
  • 複数の操作を違う順序で実行しても同じ出力になること
    • 配列をmapしてからソート、ソートしてからmap
      • arr.map(x => x + 1).sorted() == arr.sorted().map(x => x + 1)
  • 操作をしても変わらないこと
    • 配列をmapしたときの配列の長さ
      • arr.length == arr.map(x => x + 1).length
    • 配列をソートしたときの各要素
      • arr.sorted().forEach(x => arr.includes(x))
    • 配列を複数回ソートしたときの各出力
      • arr.sorted() == arr.sorted().sorted()

事例ベーステストでは同値クラスを網羅する入出力の組を洗い出さないとバグを検知できないことがあるが、プロパティベーステストはそれを防げる。
ただ、大量の入力でテストするのでテスト時間が長くなりやすい。
また、具体的な値がテスト内に記述されないため、直感的に理解しにくい。
事例ベーステストとプロパティベーステストを組み合わせるのが理想。