見出し画像

第201回: 「ソフトウェアテストしようぜ」17 GIHOZ(4. デシジョンテーブルテスト前編)

◀前の記事へ 次の記事へ▶


≡ はじめに

前回は、ペアワイズテストの後編ということで、GIHOZで組合せ表をつくってみました。大事なところを復習します。

ペアワイズテストでは、特別な機能が働かないことを確認します。
「特別な機能が働かないこと」を言い換えれば「仕様書に書かれていない組合せをつくっても悪いことは起こらない」です。
仕様書に書かれている組合せについては、GIHOZでいえば、「デシジョンテーブルテスト」や「CFD法」でテストケースを作ってテストします。

前回より

ということで今回から数回(3回になる予定)に分けて、仕様書に書かれている組合せを網羅的につくる「デシジョンテーブルテスト」の話を書きます。


≡ デシジョンテーブルテスト

デシジョンテーブルテストについては、「第93回(デシジョンテーブル前編)」と「第94回(デシジョンテーブル後編)」と「第136回(CFD法でつくるデシジョンテーブル前編)」と「第137回(CFD法でつくるデシジョンテーブル後編)」に書きました。

残すは、「原因結果グラフからデシジョンテーブルをつくる方法」くらかなと思っていました。

ところが「デシジョンテーブルの簡単化」について腑に落ちていない感じの人がチラホラいらしたので、第94回と重複するところもあるとは思いますが、「デシジョンテーブルの簡単化」に焦点を当てて書こうと思います。

湯本さんのnoteの記事」(簡単化について書いてあります)も読まれると理解が深まると思います。(湯本さんの記事だけで十分かも💦)
(なお、GIHOZのデシジョンテーブルテストのツールを使う話は次々回でする予定です。)



≡ 「簡単化」について

デシジョンテーブルの簡単化については、JSTQBのALTAシラバスの、36〜37ページに詳しい解説があります。以下に要約しました。

デシジョンテーブルの簡単化

n個の条件(各条件はY/Nの2値を持つ場合)の全組合せは2^nであるから、条件の数が増えるとデシジョンテーブルは非常に大きくなる。そこで、組合せの数を体系的に減らす技法である「簡単化」[Mosley93]が考案された。この技法では、「結果に関連性のない条件の値を「-」(関係なし)で表記する(①)」ことによって、デシジョンテーブルを簡単化する。

簡単化の方法には、上記のほかに、「ある条件値が他の条件値との組み合わせでは適用できない場合(②)」や、「2つ以上の条件が矛盾する値を持つ場合(③)」もある。

JSTQBのALTAシラバスの、36ページより要約


湯本さんのnoteの記事」によると、さらにスッキリと、デシジョンテーブルの簡単化(collapse decision table)には、以下の3つのパターンがあると書いてあります。

湯本さんの簡単化規則

・ 不可能な条件の組み合わせを含む列(上記③?)
・ 可能ではあるが現実的ではない条件の組み合わせを含む列(上記②?)
・ 結果に影響しない条件の組み合わせをテストする列(上記①?)

湯本さんのnoteの記事」より

私は、簡単化を以下のように分類しています。

・ 実行不可(Infeasible)の列を削除する(JSTQB ALTAの②と③に対応)
・ テスト不可(Untestable)の列を削除する(JSTQB ALTAで言及無し)
・ 網羅基準を全組合せからMC/DCに変えることで、デシジョンテーブルを小さくする(JSTQB ALTAの①の進化版)

一つひとつ確認していきます。まずは、実行不可から。

JSTQB ALTAの「ある条件値が他の条件値との組み合わせでは適用できない場合(②)」と、「2つ以上の条件が矛盾する値を持つ場合(③)」は実行不可能なケースを細分化したものと考えていますので、このnoteではまとめて扱います。


■ 実行不可の列を削除する

ひと言で言えば、「実行不可能な条件の組合せがある列を削除することでデシジョンテーブルを簡単化する方法」です。
補足情報となりますが、原因結果グラフでは制約を追加することで実行不可能な条件の組合せを表現しています。

例えば、制約ONEは複数の条件があったときに、どれか一つしか真(True)になれないという制約です。
これを言い換えれば、「制約ONEを指定した複数の条件が同時に真になる組合せは実行不可能」となります。

「実行不可の列を削除する」ことでデシジョンテーブルを簡単化する方法は、一番わかりやすいのではないかと思います。

具体例で説明します。以下は「うるう年」かどうかを判定するためのデシジョンテーブルです。

うるう年の判定を行うデシジョンテーブル

うるう年かどうかは、西暦年が4、100、400のそれぞれで割り切れるかどうかで決まります。条件が「4で割り切れる」、「100で割り切れる」、「400で割り切れる」の3つですから、全組合せは2³(= 2×2×2)の8通りです。
上記のデシジョンテーブルが8列なのは、全組合せを載せているからです。

全組合せのデシジョンテーブルを効率的に手作業で作る方法

条件の行見出しを書いたらその右側に、2をn乗(nは条件の数)した列を作って、
 ・ 1つ目の条件の行の左半分をY、右半分をNに埋める
 ・ 続いて、2つ目の条件の目は1つ目の条件の行にYが入っている列の左半分をY右半分をN、1行目にNが入っている列の左半分をY右半分をNに埋める

以降、同様に前の行の連続するY/Nを半分ずつYとNにしていくと、最後の行はYNYNYNYN…となり、全組合せの表が完成します。

簡単にいえば、下に行くときに半分ずつ細かくしているだけです。
上の例ならはじめは8列を半分ずつYYYY/NNNNとし、その下の行はYYNN/YYNN、最後の行はYN/YN/YN/YNというようにセルを埋めていきます。

※ デシジョンテーブルは、左上をYから始める慣習があります。あと、YesとTrueは厳密には違うけど、YがTrueの意味となるように条件を書いた方が読み取りやすいデシジョンテーブルとなります。

全組合せのデシジョンテーブルの作り方

なお、GIHOZではボタン一つでY/Nを埋めてくれます。

GIHOZのデシジョンテーブルテスト

上の図は、GIHOZのデシジョンテーブルテストの画面で条件にA, B, Cを入力したのち、[組み合わせを生成]ボタンを押したところの画面です。

※ 作業の手順として、条件を入れてから[組み合わせを生成]ボタンを押すのでボタンは表の下にあるほうが良いと思いました。

さて、うるう年の判定を行うデシジョンテーブルで黄色にした箇所は「実行不可能な条件の組合せ」です。例えば、ルール3(列番号3)をみると、
  100で割り切れる: N
  400で割り切れる: Y
となっています。

100で割り切れないのに、400で割り切れる数はありません。実行不可能な条件の組合せです。このような実行不可能な条件の組合せがある列を残しておいてもテストできませんので削除します。削除すると、以下のデシジョンテーブルが得られます。

実行不可能な条件の組合せがある列を削除することでデシジョンテーブルを簡単化

8列あったデシジョンテーブルが4列のデシジョンテーブルに簡単化されました。(確認しやすいように列番号は元のデシジョンテーブルと対応させています)

複雑な条件の組合せによって、実行不可能な場合は、削除せずに最初のデシジョンテーブルのように“どの組合せが実行できないのか”を色でマークし、動作(結果)の行に「不可能」と書いておくこともあります。
そうすることで、簡単化のため列を削除した意図が明らかになるからです。勘違いで列を削除していた場合、誰かが気が付いてくれるかもしれないメリットもあります。削除したもののレビューは削除前と比較する必要があるので大変なのです。
しかし、列を削除しないと、表の大きさは変わらないので、表は見づらいままです。したがって列を削除するかどうかは、表の可読性とのトレードオフとなります。

※ そもそも「条件の組合せが複雑なときには、手作業でデシジョンテーブルを作らずに、原因結果グラフを使おう」という話もあります。

以上が、「実行不可能な条件の組合せがある列を削除することでデシジョンテーブルを簡単化する方法」です。

さて、これから書く話を読むと混乱するかもしれませんが、列を削除することにモヤっとしている人がいるかもしれませんので、モヤっとの正体について、もう少し考えてみます。
以下は、うるう年の判定を行うデシジョンテーブルを再掲したものです。

うるう年の判定を行うデシジョンテーブル

ルール3は、「100で割り切れないのに、400で割り切れる」という条件ですから実行不可能な列として削除しました。

さて、ここで、仮に「400で割り切れるかどうかを40で割って調べていたバグ」があったとします。「Year%400」を「Year%40」にタイプミスすることがあっても不思議ではないですよね?

このバグが存在したときに、西暦年80は、4で割り切れ、100では割り切れず(80あまり)、400では(40で割るバグにより)割り切れてしまいます。これは、デシジョンテーブルのルール3にあたります。

でも、たとえ、ルール3の列を削除しなかったとしても、ルール3のテストデータとして80をテストしようと思う人は滅多にいないと思います。

「100で割り切れないのに、400で割り切れる」現象(バグ)があると想定して、そこからどのような欠陥があればそういう現象になるかなと推定して80をテストデータとして採用する人はいるかもしれません。でも、その人は“神テスター”です。

※ミッションクリティカルなシステムの場合、あり得ないケースを含めてロジックツリーをつくってしらみつぶしに評価するというのはよく行われています。
また、FTAなども、トップ(頂上事象)に発生を予防したい事象(もしくは、発生したレアケースの不具合事象)をおいて、「もし、その事象が発生するなら、、、」と問いかけることによって頂上事象を発生させる原因を見つけます。
ただ、ロジックツリーとFTAはどちらも莫大な評価工数がかかりますので、全てのテストで行われるようなものではありません。

”はじめに”に書いたとおり、「デシジョンテーブルテスト」は「仕様書に書かれている組合せを網羅的につくる」テスト技法です。したがって、「たとえ、全組合せを実施したからといって、全てのバグが見つかるとは限らない」という点に注意しましょう。デシジョンテーブルテストは、組合せロジックに対して網羅的にテストを行うだけです。

網羅的ということは、網をすり抜けるバグもあるということです。
ただし、魚を採るときに細かい網であれば、そこをすり抜ける魚は小さいもののみであることと似て、テストの網羅基準を細かくすれば、大きなバグの見落としは減ります。

最後に、「ある条件値が他の条件値との組み合わせでは適用できない場合」について、JSTQB ALシラバスに事例がありましたので以下に転記します。

カード決済のデシジョンテーブルでは、「カードが有効」という条件が偽の場合、「PIN コードが正しい」という条件は適用できない。

出典: JSTQB ALシラバス 36ページ



■ テスト不可の列を削除する

続いて、「テスト不可能な条件の組合せがある列を削除することでデシジョンテーブルを簡単化する」方法について書きます。

「テスト不可能」と「実行不可能」の違いは分かりにくいですね。私も、原因結果グラフからデシジョンテーブルをつくる方法を調べているときに、最初は、「同じじゃん? 言葉遊び??」って思いました。

「テスト不可能な条件の組合せがある列を削除することでデシジョンテーブルを簡単化する」を言い換えれば、「仕様に記載のない組合せがある列を削除することでデシジョンテーブルを簡単化する」方法です。
「テスト不可能」を簡単に言うと、「実行はできるが、正しい実行結果が分からないからテストにならない」です。

※ 実は、「テスト不可」にはもう一つ、「結果が論理的に一つに決まらない」パターンもあるのですが、そちらは超レアです。
超レアなので、デシジョンテーブルで列ごと消して簡単化するのではなく、テスト中に「あれ? このテストできないじゃない!?」ってなって、仕様改善要望を出す方が良いと思います。

閑話休題。テスト不可の話にもどります。
個々の条件をリストして組合せをつくると、仕様をつくるときに想定漏れをしていた組合せがでて、仕様にないためテストの実行結果(期待値)をつくることができない場合があります。例えば、以下の仕様を考えてみます。

■ 入場券の割引仕様

団体の小学生は200円引きとなるが、個人の小学生は100円引きとなる

「団体と小学生には、割引が適用されるのね」とわかった感じになります。(ここで仕様の不備に気が付いたあなたは鋭いです)

上記仕様から、デシジョンテーブルをつくってみます。

ルール1とルール2は「団体でかつ個人」なので、実行不可能な組合せ条件になりますので、列ごと削除できます。

さて、ルール7とルール8は「団体でも個人でもない」組合せ条件です。「団体でも個人でもない」組合せ条件にマッチする人が存在するかどうかについて、この仕様からはわかりません。
例えば、団体枠と、個人枠の他に地元枠があり、「地元の小学生は300円引き」という仕様に記載のない、隠れたルールがあるかもしれません。

このように、仕様の抜け漏れを見つけるために、デシジョンテーブルで全組合せをつくることは役に立ちます。

テスト設計でデシジョンテーブルをつくったときにこのような仕様漏れに気が付いたときには、「仕様を確認をする」ことになります。
仕様の確認ができるまでは、こちらのルール7とルール8のテストをしても「期待結果」がないため、テスト結果の正しさを評価することができません。
そこで、テストにならない(テストが不可能な)組合せがある列を削除して、デシジョンテーブルを簡単化します。

仕様書に定義されていない組合せがある列も削除することでデシジョンテーブルを簡単化

以上が、「テスト不可能な条件の組合せがある列を削除することでデシジョンテーブルを簡単化する」方法です。

こちらもモヤっとしそうな点について書きます。

このときに、「仕様が無くても、テストすることによって分かるものだってあるだろう? 出てきた結果について仕様はわからずともテスターとして納得いくものかどうかの意見はだせるでしょう? また、クラッシュしない等の当たり前のことの評価はできるでしょう?」という意見があります。

はい。その通りです。

でも実際にテストをすべきかどうかは、「テスト不可能な組合せ対してテストすることの合意」の問題です。

どこまでテストするか、そのテストに対価は支払われるのか、そのテストでテスターとして納得がいかなかったときに気持ちよく対応してくれるのか、等々の合意がとれていれば「テスト不可能な組み合わせについて簡単化せずにテスト実行してみる」という選択肢もあります。


■ 網羅基準を全組合せからMC/DCに変える

こちらについては、プログラムコードの情報を活用することもでき、少し複雑なので次回説明します。(今回のnoteは、すでに7000文字と、長文になってしまったのと、デシジョンテーブルの簡単化というと、この方法を思い浮かべる人が多いようなので丁寧に書きたいのです)



≡  おわりに

今回は、「デシジョンテーブルテスト」の簡単化の方法の「実行不可能な列を削除する」と「テスト不可能な列を削除する」について書きました。

テスト不可能が理由の簡単化については、仕様が明らかになるまでは削除しても構いませんが、基本的には仕様を明らかにしてテストすべき組合せです。
(バグがひそんでいる可能性が高いため、最後までテストできない場合はリリース後のリスクになります)

また、実行不可のテストに対しても、“その実行不可の組合せが実行できないようにガードする機構がソフトウェアに実装されていること”を確認するテストが別途必要です。

さて、ここまで読んで、「だったらデシジョンテーブルの簡単化なんてせずに全ての組合せをテストした方が良い。だって、簡単化は難しいから間違える可能性もあるからしたくない。」と思われたかもしれません。でも、それは違います。

テストには目的があり、目的を果たすために効率よくテストをする必要があります。無限のテスト時間があるわけではないからです。
ですから、「論理的組合せを確認するテスト」と、「実行不可の条件の組合せをガードする機構のテスト」を分けることで、テストの総数が減りテスト全体の効率化が出来るのでしたら、そうすべきです。多くの場合、それは可能です。

もちろん以前も書きましたが、「巨大化しないのなら、デシジョンテーブルを作らずに全組合せのマトリクスを作ってテストする方が良い」も真実ですし、「仕様に書いていないのだからテストではペアワイズの網羅性の保証レベルとする」という考え方(アプローチ/戦略)もあるでしょう。

どのアプローチを選ぶのかについては、状況をよく見極めて決めます。

あー。そーいうことだったのか。
書き始めたときには、なんでみんな“デシジョンテーブルの簡単化わからん!”って言うんだ?と思っていたけど、こういう見極めが難しいっていっていたのかもー。

次回は、「網羅基準を全組合せからMC/DCに変えることで、デシジョンテーブルを簡単化する」話について書こうと思っています。

◀前の記事へ 次の記事へ▶


いいなと思ったら応援しよう!