| name | blackbox-cause-effect |
| description | 条件の論理関係や入力の多次元構造から、組合せを縮約してテストを導くブラックボックス技法群。 test-catalog の手法カタログの一部。原因結果グラフ(Cause-Effect Graph、AND/OR/NOTでデシジョンテーブルを機械導出)、 クラシフィケーションツリー法(Classification Tree Method、分類軸を同値クラスへ細分し葉の組合せを選ぶ) を検証したい、または割り当てたいときに使う。通常は test-catalog スキルの索引経由で 手法が選定された後にこのスキルを直接参照する。
|
| disable-model-invocation | true |
ブラックボックス設計技法(論理ベースの組合せ縮約)
条件の論理関係や入力の多次元構造から、組合せを縮約してテストを導く技法群。
ここでは、条件と結果の論理関係をグラフ化して導く原因結果グラフと、入力を分類軸へ構造化して導くクラシフィケーションツリー法をまとめる。
独立した因子の2要因被覆や均等割付でケースを縮める因子被覆系(ペアワイズ、直交表、T-way)は blackbox-covering.md を参照。
これらも独立して使うものではなく、入力空間の分割技法の上に重ねる。
条件の論理関係が複雑なら原因結果グラフ、入力が複数の独立した側面を持つならクラシフィケーションツリーへ進む。
入力空間の分割(同値分割、境界値分析、デシジョンテーブル)は blackbox-partition.md を、履歴と状態(状態遷移、CRUD/ライフサイクル)は blackbox-state.md を参照。
目次
原因結果グラフ(Cause-Effect Graph)
概要
入力条件(原因)と出力(結果)を論理ゲート(AND/OR/NOT)で結んだグラフを描き、そこから機械的にデシジョンテーブルを導出する。
目的/いつ使う
条件と結果の論理関係が複雑で、デシジョンテーブルを手で作ると組合せを取りこぼす恐れがあるときに使う。
グラフ化すれば論理の矛盾や冗長を先に発見できる。
関係が単純ならグラフは省き、直接デシジョンテーブルでよい(YAGNI)。
TypeScript example
原因結果グラフ自体は設計の中間成果物で、最終的にはデシジョンテーブルへ落ちる。
そのテーブルを「デシジョンテーブル」と同じ it.each 形式でテストする。
グラフから導いた論理式をコメントで残すと追跡しやすい。
import { describe, it, expect } from "vitest";
import { canWithdraw } from "./atm";
describe("canWithdraw: derived from cause-effect graph", () => {
const t = true, f = false;
const cases = [
{ c1: t, c2: t, c3: t, expected: true },
{ c1: f, c2: t, c3: t, expected: false },
{ c1: t, c2: f, c3: t, expected: false },
{ c1: t, c2: t, c3: f, expected: false },
] as const;
it.each(cases)(
"card=$c1 funds=$c2 limit=$c3 -> $expected",
({ c1, c2, c3, expected }) => {
expect(canWithdraw(c1, c2, c3)).toBe(expected);
},
);
});
落とし穴
- グラフ作成のコストが高い。論理が単純な場面に持ち込むと、得るものより手間が勝つ。
- 制約(原因間の排他、包含)をグラフに書き落とすと、実現不可能な組合せをテストしてしまう。
網羅の定義
- 網羅基準:グラフから導出したデシジョンテーブルの実現可能な全ルールを網羅したとき完了(デシジョンテーブルの基準を継承する)。
- 網羅手順:
- 原因と結果を論理ゲート(AND/OR/NOT)でグラフ化する。
- 原因間の制約(排他、包含)をグラフへ反映する。
- グラフを機械的にデシジョンテーブルへ変換する。
- 残った各ルールを1ケースにする。
- 達成チェック(もれ確認):
- 全ルールに代表が割り当たったか:導出したデシジョンテーブルの実現可能ルール数と、テストケース数が一致する。差があればルール取りこぼし=網羅に穴。
- 各結果(E)に真と偽の両方の代表があるか:結果ごとに、それを真にするルールと偽にするルールが少なくとも1本ずつテストにある。片側しか無ければ、その論理ゲートの効きを確かめられていない。
- 各原因(C)が結果に効く組合せを踏んでいるか:原因 Ci を反転させたとき結果が変わるケースが各 Ci に1本以上ある(他の原因を固定して Ci だけ動かす)。無ければその原因の寄与が未検証で、論理式の項を1つ素通りしている。
- 実現不可能な組合せを混ぜていないか:原因間の制約(排他、包含)で到達不能になる行をテストに入れていない。
grep でテストデータを目視し、禁止された原因の同時真/同時偽が無いか逆引きする。
クラシフィケーションツリー法(Classification Tree Method)
概要
テスト対象の入力をいくつかの分類(classification)に分け、各分類を同値クラスへ細分してツリーで可視化し、ツリーの葉の組合せからテストケースを選ぶ。
同値分割を多次元へ構造化したものである。
目的/いつ使う
入力が複数の独立した側面を持ち、各側面ごとに区分が要るときに使う(画像処理での、フォーマット × サイズ × カラーモードなど)。
ツリーで網羅状況を見ながら、ペアワイズなどと組み合わせて組合せ数を制御できる。
側面が1つなら単なる同値分割で足りる。
TypeScript example
分類(フォーマット、サイズ)とその葉を配列で持ち、選んだ組合せを it.each で回す。
ツリーは設計図、テストはその葉の選択にあたる。
import { describe, it, expect } from "vitest";
import { thumbnail } from "./image";
const selected = [
{ format: "png", size: "small", ok: true },
{ format: "jpeg", size: "huge", ok: true },
{ format: "webp", size: "empty", ok: false },
] as const;
describe("thumbnail: classification tree leaves", () => {
it.each(selected)("$format/$size -> ok=$ok", ({ format, size, ok }) => {
expect(thumbnail(format, size).ok).toBe(ok);
});
});
落とし穴
- 分類が直交していない(side effect で絡む)と葉の組合せが誤誘導になる。分類軸の独立性を先に確かめる。
- 葉を全組合せで取ると爆発する。ペアワイズや優先度で間引く。
網羅の定義
- 網羅基準:選んだ組合せ戦略(全葉単独、2-way、優先度)に対し、その戦略が要求する葉の選択をすべて踏んだとき網羅完了。
- 網羅手順:
- 入力を独立した分類軸へ分ける。
- 各軸を同値クラスへ細分する。
- ツリーの葉を列挙する。
- 組合せ戦略を選び、その戦略に従って葉の組合せを選択し1ケースずつにする。
- 達成チェック(もれ確認):
- 全ての葉が最低1回出たか:各分類軸ごとに、その軸の葉(同値クラス)を列挙し、選んだケース集合の中で各葉が少なくとも1度現れるか数える。出ていない葉があれば、その同値クラスが丸ごと未テスト。戦略が全葉単独でも 2-way でも、この「各葉1回以上」は最低線として満たす。
- 選んだ戦略の要求を満たしたか:2-way 戦略なら任意の2軸間の全葉ペアが1度は出ているか、優先度戦略なら高優先と決めた葉の組合せが漏れず入っているかを、戦略の定義に照らして逆引きする。
- 分類軸の独立性が崩れていないか:軸 A の葉を選ぶと軸 B の取りうる葉が変わる(side effect で絡む)組合せをケースに入れていないか確認する。絡む軸があれば、その葉の組合せは誤誘導なので、軸を分け直すか実現不可として除外する。
- 葉の全組合せが爆発する場合、戦略(ペアワイズ、優先度)で間引けているかを見る。
独立した因子の被覆で縮約する技法(ペアワイズ、直交表、T-way)は blackbox-covering.md を参照。
入力空間の分割は blackbox-partition.md を、履歴と状態は blackbox-state.md を参照。