第202回: 「ソフトウェアテストしようぜ」18 GIHOZ(5. デシジョンテーブルテスト中編)
◀前の記事へ 次の記事へ▶
≡ はじめに
前回は、「デシジョンテーブルテスト」の簡単化の3つの方法のうち、実行不可と、テスト不可について説明しました。復習を兼ねて、3つの方法を再掲します。
・ 実行不可(Infeasible)の列を削除する
・ テスト不可(Untestable)の列を削除する
・ 網羅基準を全組合せからMC/DCに変えることで、デシジョンテーブルを小さくする
今回は、「網羅基準を全組合せからMC/DCに変えることで、デシジョンテーブルを小さくする」話について書きます。
前回と今回は、「簡単化」に焦点をあてているために、すべての条件がYとNや、TrueとFalseといった2値を持つケースで説明しています。
すべての条件が2値(バイナリ)であるデシジョンテーブルのことを英語でLETD(Limited Entry Decision Table)と呼びます。たまに出てくる略称なので記憶の片隅に置いておくとよいかもしれません。(わからなかったらその場で、「LETDって何ですか?」と質問をすればよいだけですが)
なお、LETDに対して、条件が3つ以上の値を持つことができる場合のデシジョンテーブルは、EEDTs (Extended Entry Decision Tables)と呼びます。
私はLTEDやEEDTsという用語は使わずに、「条件はYとNの2値を取る」、「条件は多値も取る」ということが多いです。
※ 専門用語は大切、、、といいますか、知っている人同士で使うと大変便利です。
でも、専門用語を覚えるよりも、「条件は入力の同値クラス(同値パーティション)、動作はテスト対象の主要な機能処理部分を指す」ということを理解しているほうが、ずっと大切と思います。
≡ 結果に関連性のない条件
私がおすすめしている「網羅基準を全組合せからMC/DCに変えることで、デシジョンテーブルを小さくする」方法は、JSTQB ALTAの「結果に関連性のない条件の値を「-」(関係なし)で表記することによって、デシジョンテーブルを簡単化する」方法に近いので、まずは「結果に関連性のない条件の値を『-』(関係なし)で表記する」方法について具体例を示しながら説明します。
「結果に関連性のない条件の情報」を使ってデシジョンテーブルを簡単化する方法には、大きく、Mosleyのデシジョンテーブルの簡単化(1993)と、Elmendorfの原因結果グラフ(1973、その後、マイヤーズの著者によって広まり、SoftTestなどの商用ツール化時に改善が加えられた方法)を用いた簡単化の2つの方法があります。私は後者を好んで使用しています。
※ SoftTestとその後のBenderRBTの歴史は、こちらのページにあります。わりと面白いです。このページには、“He is the initial developer of equivalence class testing with boundary analysis.”と書いてあります。
このHeはWilliam Elmendorfを指しています。彼は、原因結果グラフの論文を書いただけではなく、境界値分析を伴う同値クラスの最初の開発者だったようですね。
※ SoftTestは、BenderRBTとなったって書いてありますが、その間に、CaliberRBTという商品がありました。そして、私が使っていたのはCaliberRBTです。ちなみにRBTとは、“Requirements Based Testing”(要件をもとにしたテスト)の略です。
※ 「結果に関連性のない条件の情報」を用いた簡単化の仕組みについて以下で補足します。
例えば、「A and B」という論理式があったときには、
A B (A and Bの)結果
----------------------
真 真 真
真 偽 偽
偽 真 偽
偽 偽 偽
の4通りの結果があります。しかし、よく考えると、最後の行は、AとBのどちらの偽が結果に影響を与えたのかわかりません。and演算子は片方が偽のときには、もう片方が真でも偽でも結果は偽に決まっているからです。
わからないのならテストをしても無駄なので「偽 and 偽」のテストは不要(テストの優先順位を下げてよし)と考えます。
そして、その組合せ条件をデシジョンテーブルから外すことによって簡単化します。
今回の例題の仕様は以下の通りです。
舞妓さんになるには、次の3つの条件をクリアする必要がある。
1. 年齢は15歳から20歳
2. 身長は160㎝未満
3. 女性
あー、スリーアウト。
私は完璧に対象外だ。(笑)
さて、デシジョンテーブルをつくってみます。

上記のデシジョンテーブルをみると、年齢の条件がN(条件に当てはまらない)なら、他の条件がどうであれ、舞妓不可であることがわかります。
そこで、結果に関連性のない条件の値を「-」(関係なし)に置き換えます。
ここで、「-」と「DC」と「N/A」の違いが気になる人がいらっしゃるかもしれません。
「DC」は「-」と同じ意味で、“don't care”の略です。“don't care”は、「どうでもいい」「気にしない」「知ったこっちゃない」という意味です。デシジョンテーブルでいえば、「-」は「YとNのどちらでもよい」という意味になります。
一方、「N/A」は“Not applicable”の略ですから、「適用できない」という意味です。
※ “Not Applicable” は一般には記入用紙の空欄を埋める際などに用いられます。選択肢の中に該当するものがない場合(例えば、問診票の「妊娠中ですか?」との問いに対して、「男性なのでN/Aです」とか、、、そういう感じです)や、自分には記入すべき事柄が存在しない場合などに(空欄だと未検討と区別がつかないので)「N/A」で埋めます。
状態遷移表の空欄(イベントが届いても無視される)に「N/A」と記されることが多のはこのことからです。まとめます。
・ ハイフンまたはDC: 値は何でも構わない
・ N/A: 中止/中断/未定/禁止などの理由から適用できない

上記は、年齢の条件がクリアしなかった場合(Nのとき)には、身長の条件や性別が女性という条件は結果に関連性がないことを示しています。5~8列は全て同じ内容なので1列を残してあとは削除します。

ここで簡単化を終えてしまうことも一つの手だとは思います。「間違いが少ない割に大きくテストケース数を削減できる」からです。
でも、勇者は先に進んでほしいと思います。
このデシジョンテーブルをよく眺めていると、年齢の条件がYで身長条件がNの3列と4列については、性別が女性という条件がYでもNでも結果が変わらないことが分かります。そこで3列と4列に対して、女性行のセルのYとNを「-」で置き換えます。

置き換えてみると、3列と4列は同じ内容となったので、3列を残して4列は削除します。(4列のほうを残しても同じことです)

こちらで、「結果に関連性のない条件の値を「-」(関係なし)で表記することによって、デシジョンテーブルを簡単化する」方法で、デシジョンテーブルの簡単化ができました。
今回は説明のために「ハイフンを入れてから同じ内容になった列を削除」していますが、実務上は、「同じになる列を見つけて1列を残し、ハイフンを埋める」ようにすることが多いです。
続いて、「モヤっとポイント」について説明します。
まず、もとのデシジョンテーブルを再掲します。

最初の説明では、年齢(N)から始めましたので、今度は、身長(N)から始めてみます。

身長がNの列に着目すると、どれも結果が同じです。そこで、他の条件を「-」に置き換えてみます。

3, 4, 7, 8列が同じになりました。同じ列(同じテストケース)を何度もテストする必要はありませんので、列を1つ残してあとは削除します。

よくみると、5列と6列は、女性がYであってもNであっても結果は同じです。

同じ列ができたので簡単化します。

ここで、年齢からはじめたものと比較してみます。

1列目と2列目は全く同じですが、3列目と4列目は「-」が入っている位置が違います。
例えば、右側のデシジョンテーブルをみると、3列目の年齢は「-」です。
さて、ここで、「-」はYでもNでも構いませんので、「N」を入れてみます。

もし、条件が上から順番に処理されるのなら、右側のデシジョンテーブルでは、ルール3で年齢で不合格になったら身長(N)のチェックは行われません。身長がNの値を持つ列は第3列のみですので、身長がNだったときの結果を確認する列がありません。
どうやら、「結果に関連性のない条件の値を『-』(関係なし)で表記することによって、デシジョンテーブルを簡単化する方法」をおこなうときには、条件が処理される順番を考慮する必要がありそうです。
≡ 処理の順番について
まず、条件の処理の順番を考慮しないとどうなるかについて確認します。
デシジョンテーブルの簡単化のときに条件側に入力した「-」は「関係なし」の意味ですから、任意の有効な値(この場合ならYとNのどちらでも)セットすることができます。

そこで、上記のデシジョンテーブルでは最初のデシジョンテーブルの条件の「-」を「N」に置き換えてみました。
さて、ここで、開発者が、女性→年齢→身長の順番でチェックするようにプログラムコードを書いたとします。
デシジョンテーブルを実行順に並び替えてみます。

1列目のテストでは、女性(Y)、年齢(Y)、身長(Y)のテストがおこなわれます。2列目以降のテストでは女性がNなので、他の条件はチェックされず「舞妓不可」の結果を出します。したがって、年齢と身長については、列1のテスト、すなわち、値がYのテストしかされません。
もしも、プログラマーがつくったプログラムが元のデシジョンテーブルの行の順番と同じ条件の順(年齢→身長→女性の順)で処理をしていたら、以下の表のように、列の2では女性がNの条件を列の3では、身長がNの条件をテストしています。

このことからデシジョンテーブルを「結果に影響しない条件の組み合わせをテストする列」を削除する方法で簡単化するときには、「処理の順序」通りに条件行を並べてから、下の行から上に向かって順番に簡単化する必要があります。
「下の行から」については、上の図では説明をしていませんが、要は「最後の一つの判断処理の時に結果が変わらないのならそれ以前の処理で結果が確定している」ということです。
「-」でデシジョンテーブルを簡単化する方法をまとめます。
1. 条件は、プログラムの処理順に上から書く
2. 以降の処理が関係ないときにハイフンで埋める
(簡単に言うと、下から上に向かって「-」を埋める)
3. 同じ列を1列だけ残すことでデシジョンテーブルを簡単化する
≡ 処理の順序が分からない場合
デシジョンテーブルの簡単化をするときに、ソースコードをテスト設計者がみることができない状況や、開発者とのコンタクトができない状況があります。また、そもそも、ソースコードが存在しない要件リストに対して早期にテスト設計することがあります。
はじめのほうに書いた、RBT(Requirements Based Testing: 要件をもとにしたテスト)では、要件からテストケースをつくりますので、処理の順序の仕様はありません。
さらに、心配性な人は、「実装の順番なんていつ変わるかわからない」と考えるかもしれません。
その場合は、今回であれば、「-」を「N」ではなく「Y」に置き換えます。

そうすると、順番を並び替えても、

のようになり、Nの上には必ずYが連続してありますので、各条件のYとNが評価されます。
ちょっとした手品のようですが、2列目では女性がN、3列目では身長がN、5列目では年齢がNのときに舞妓不可となるテストが出来ています。(書くまでもないかもしれませんが1列目では女性がY、身長がY、年齢がYのそれぞれが結果に影響を与えています)
このように、各条件のYとNというCondition(条件)と結果を決めるDecision(判定)をともに満たすので、これを改良条件判定テスト、略してMC/DCと呼びます。改良条件判定テストについてISTQBの用語集では以下のように定義しています。(ソースコードの制御フローパステストで使われることが多いため、ホワイトボックステスト技法に分類されているのかもしれません。説明してきたようにブラックボックステストでも使用するのですが)
改良条件判定テスト(modified condition / decision testing)
ホワイトボックステスト設計技法の一つ。判定結果に対して独立に影響する単一条件結果を実行するテストケースを設計する。
さて、MC/DCカバレッジを満たすように「-」をYまたはNに変更する方法ですが、条件がANDで結ばれているときには上で書いたようにYに置き換え、条件がORで結ばれているときにはNに置き換えるのが基本です。
ANDとORが混在する複雑な場合は、手作業だと誤りが生じますので原因結果グラフを用います。
もともと、デシジョンテーブルテストの簡単化が必要なのは、多くの意思決定が行われる場合です。多くの複雑な論理構造があるテストに向いているのですから、「Mosley, D.J., The Handbook of MIS Application Software Testing, Yourdon Press, Prentice Hall, Englewood Cliffs, NJ, 1993.」よりも、原因結果グラフ(Elmendorf,1973の進化版)を使うことをおすすめします。
一方で、そんなに複雑な論理構造があるようになっているプログラムが悪いという話もあります。たとえば、いい加減なクラス設計のつけをテストが払っているのなら、いい加減なクラス設計を改善すべきであり、テストで頑張りすぎないほうが良いのかもしれません。
原因結果グラフについては、GEGTestを使うと便利です。原因結果グラフとCEGTestの使い方の解説は、拙著『ソフトウェアテスト技法ドリル【第2版】』に書きました。
Bender RBT Incのツールも原因結果グラフの良いツールです。しかし、日本で販売していないので輸入してもサポートを受けるのは困難です。
また、古川善吾先生が作ったAGENTというツールもあるのですが、AGENTは販売していません。(AGENTは、そもそも日立の大型コンピュータで動作していた社内用のツールです)
≡ 練習問題
2回に渡って、デシジョンテーブルの簡単化について説明しました。
わかったかどうかモヤモヤしている人がいるかもしれません。そこで、練習問題を用意しました。
解いてみてみて。
大規模イベントを開くにあたり、警備員を1名募集することになった。その条件は以下の通りであり、条件に当てはまれば報酬額を当てはまらなければ“不採用”を出力するものとする。
1. 身長: 180cm以上
2. 性別: 男性
3. 報酬: 経験者3万円、未経験者2万円
上記について、デシジョンテーブルを作成して簡単化せよ。
※ プログラムは、2→1→3の順に処理している。
解いたらTwitterで@akiyama924に簡単化の前後のデシジョンテーブルやコメントをメンションしていただけると次回のGIHOZの回で使えるので非常に助かります。🙇♂️
もちろんGIHOZを使っても構いません。手書きでもいいです。
≡ おわりに
今回は、「デシジョンテーブルテスト」の簡単化の3つ目として、「網羅基準を全組合せからMC/DCに変えることで、デシジョンテーブルを小さくする」方法について書きました。
処理の順番の情報が得られれば、MC/DCでなくても、条件を処理の順番に並べるだけで、それぞれの条件のYとNがテストされます。したがって、原因結果グラフが苦手な方は処理の順番に合わせて、デシジョンテーブルを作ると良いでしょう。
ところで、処理の順番を変えることで、ロジックがシンプルになることがあります。前回書いた「うるう年の判定」についても、4→100→400の順番で判定処理を書くよりも、400→100→4の順番で処理する方が楽です。(400だったら「うるう年」をリターンして関数を抜け、、、と書けばよいからです)
そこで、デシジョンテーブルテストの作成が上達したらデシジョンテーブルを開発者と一緒になって考えるのもよいでしょう。
その際には、デシジョンテーブルをつくる前にデシジョンツリーで検討する方が良いです。デシジョンツリーについては、『ソフトウェアテスト技法練習帳』の第2章が参考になります。
Jorgensenも“how good testing can improve programming.”と書いていました。
デシジョンテーブルテストの理解のために、Jorgensen (https://t.co/7SthaCuHgr)を読んでいるのだけれど、「優れたテスト設計を開発の詳細設計時におこなうことでプログラムを向上できる」ようなことが書いてあった。
— あきやま🍁 (@akiyama924) November 7, 2022
次回は、いよいよGIHOZの「デシジョンテーブルテスト」ツールを使い、GIHOZのテストをつくります。
