ソフトウェアの品質を学びまくる2.0

ソフトウェアの品質、テストなどについて学んだことを記録するブログです。

ソフトウェアテスト技法の使い間違いって何? 彼氏はいるの? 性格が悪いって本当? 調べてみました!#テストアドカレ

 この記事は、ソフトウェアテストの小ネタ Advent Calendar 2018、17日目の記事です(先走り)。

qiita.com

 16日は、mktkさんの以下の記事でした。

panmania.hatenadiary.com

15216848023_d54c7e6344_o無意味な風景画像

0. テスト技法の「使い間違い」

 テスト技法にはそれぞれ使い所があり、また使う上での注意点があります。使い方を間違えると、良いテストを作るはずが、逆の効果をもたらしかねません。
 この記事では、テスト技法の使い間違いによってテストケースが漏れてしまう様子を、『ソフトウェアテスト技法ドリル』の例題を使って眺めてみましょう。

ソフトウェアテスト技法ドリル―テスト設計の考え方と実際

ソフトウェアテスト技法ドリル―テスト設計の考え方と実際

1. デシジョンテーブル: 実装を無視して圧縮する!

1-1. 圧縮とは?

 『ドリル』の第3章では、デシジョンテーブル(決定表)を扱っています。
 この章の例題の仕様は、ざっくり以下の通りです。

「商品カテゴリーが書籍である」 かつ 「価格が1,500円以上である」 かつ 「配送先が離島でない」 場合に「送料が無料」となる。

 3つの条件がそれぞれ「真」「偽」の2つの値を取るので、完全なデシジョンテーブルの列数は23=8になります。

テストケース12345678
条件書籍であるTTTTFFFF
1,500円以上であるTTFFTTFF
離島でないTFTFTFTF
動作送料無料TFFFFFFF

 ですが、場合によってはこれを「圧縮」することができます。『ドリル』から引用します(太字筆者、以下同様)。

圧縮とは、列をまとめて総規則数を減らすことです。その方法は同じ動作(結果)をもつテストケースのなかで、結果に影響を及ぼす行が1行しかなかった場合、その列をまとめて結果に影響を及ぼす行のセルを「Y」でも「N」でもどちらでもよいという意味で「ー」に変更するという方法です。

 圧縮したデシジョンテーブルは以下のように8列が4列になっており、半分のテストケースが削減できることになります。

テストケース1234
条件書籍であるTTTF
1,500円以上であるTTF
離島でないTF
動作送料無料TFFF

1-2. 圧縮の注意点と具体例

 デシジョンテーブルの圧縮には、重要な注意点があります。

このときに重要となるのは、条件が処理される順番です。どの規則も、品物、合計金額、配送先の順で処理されるから...圧縮できるのです。

 つまり、プログラムの実装を無視して圧縮すると、本来必要なテストケースが漏れることがあるということです。
 直感的には理解できるのですが、いざ「じゃあどんな場合?」と考えたときに、例がパッと出てこなかったため、考えてみました。
 以下のような仕様としましょう。

  • 仕様1: 書籍 かつ 1,500円以上 かつ 離島以外 なら、配送料無料
  • 仕様2: 書籍 かつ 1,500円以上 かつ 離島 なら、配送料300円
  • 仕様3: 書籍 かつ 1,500円以上でない なら、配送料400円
  • 仕様4: 書籍でない かつ 離島以外 なら、配送料500円
  • 仕様5: 書籍でない かつ 離島 なら、配送料1,000円

 この順番のまま素直にデシジョンテーブルを作ると、以下のようになります。

テストケース12345
条件書籍であるTTTFF
1,500円以上であるTTF
離島でないTFTF
動作送料無料無料300円400円500円1,000円

 ドリル本の圧縮テーブルとの違いは、#4と#5です。ドリル本では、書籍がF判定だった時点で結果は1つだったのですが、こちらはもう一度判定が必要になります。
 ハイフンは「TとF、どちらでもよい」ので、たとえばここではともに「T」を指定することにしましょう。

テストケース12345
条件書籍であるTTTFF
1,500円以上であるTTFTT
離島でないTFTTF
動作送料無料無料300円400円500円1,000円

 このまま実装すると、こんな感じでしょうか。

 一方「離島でないか否か」の方から判定を始めると、以下のようになるでしょうか。

 どちらにせよ、上のデシジョンテーブルに基づくテストケースはすべてパスします。

 しかし・・・
 ここで2つ目のプログラムの12行目を誤って「4,000」としてしまったとします。この場合、上の5つのテストケースでは検出が漏れます。テストケースT-F-Fのケースが、圧縮によって省略されたためです。
 配送料を代入する式が6つあるのにテストケースは5つしかないので、漏れるケースがあるのはある意味当たり前ですね。

2. オールペア法: 有則の組み合わせに用いる!

 無則の組み合わせテスト技法である「直交表」や「オールペア法」を学ぶと、「パラメタが多い場合の組み合わせは、組み合わせテスト技法で大幅削減できるんだ!」というところだけを記憶してしまうリスクがあります。

 上のデシジョンテーブルの例では、3つの条件に対し組み合わせが8つもあるし、圧縮するには実装を意識しないといけないから大変だなあ・・・そうだ! オールペア法を使おう!と突き進んでしまうと失敗します。
 ためしに、3つの「条件」をパラメタと考えて、PictMasterで組み合わせてみましょう。

pictmaster

 PICTMasterに入力して・・・ポン!

品物は書籍合計は1,500円以上配送先は離島以外
TFT
TTF
FFF
FTT

 よーし、組み合わせ数が半分に減ったぞ・・・って、えーーー!
 一番肝心な、「送料無料」になるケースが出てこない・・・。

 無則の組み合わせテスト技法は、組み合わせるパラメタ同士が影響しない(ことになっている)場合に利用するものであり、強度2では、3パラメタ間の特定の組み合わせの出現を保証しません。影響し合うパラメタの組み合わせに用いてはいけないことが確認できましたね。

3. 状態遷移テスト: 2スイッチカバレッジ100%で1スイッチカバレッジも網羅!

 最後に、状態遷移テストのスイッチカバレッジにおける使い間違いを見てみましょう。「nスイッチカバレッジ」というのは、状態遷移をn回行う遷移パターンの網羅率のことです。

 たとえば以下のような状態遷移図を考えてみましょう。

stateMachine

 これを状態遷移表で表現すると、以下のようになります。

SABE
Sa
Abc
Bd
E

 この各セルの状態遷移をすべて実行すれば、1スイッチカバレッジが100%ということになります。
 2スイッチカバレッジであれば、状態S→状態A→状態B のような、2回の状態遷移パターンの網羅率を指すということです。

 さて、ここで気になるのは、nスイッチカバレッジが100%の場合、n-1以下のスイッチカバレッジは自動的に100%になるのか、という点です。
 無則の組み合わせテストでは、強度nのカバレッジが100%なら、強度n-1以下のカバレッジも100%になります。コードカバレッジでも、判定網羅が100%なら命令網羅も100%になります。

 『ドリル』では以下のように説明されています。

ここで、注意しなければならないのは、2スイッチカバレッジを行うだけでは、状態遷移表や1スイッチカバレッジのテストをしたことにはならない場合があるという点です。状態遷移がループしていない場合に、1スイッチはできても2スイッチできないケースがあるからです。

 試しに、2スイッチカバレッジのパターンを見てみましょう*1
 まず、関係行列は以下の通り。

 この行列を掛け算すると・・・。このような行列になります。 

 たとえば右上に「ac」が出ていますね。これは、状態Sから始まって、遷移aによって状態Aへ。さらに遷移cによって状態Eへ。という2スイッチのパターンとなります。この中には、1スイッチの遷移a~dも含まれており、2スイッチカバレッジ100%は、1スイッチカバレッジ100%も満たしているようです。

 さらに掛け算して、3スイッチカバレッジを見てみましょう*2

 3スイッチの遷移パターンは、たった34つになってしまいました。2スイッチであったパターン5個のうち、状態Sから始まる「ac」と、状態Bから始まる「5cdc」が消えてしまっています
 行列計算上、acも5cdcも掛け算対象が0になっているため、消えてしまうのです。状態遷移図で見ると自明で、Eから遷移する先はないので、S→A→E、B→A→Eで止まってしまうのですね*3

 このように、nスイッチカバレッジを100%にしたからといって、n-1以下のスイッチカバレッジが100%になるとは限らないということがわかりました。

まとめ

 いかがでしたか?
 テスト技法の使い方を間違うと、重大なテストケース漏れが起こることを実感いただけたでしょうか。
 みなさんもぜひ、テスト技法の誤った使い方について調べてみてくださいね!

*1:2スイッチカバレッジのパターンの導出方法は『ドリル』で詳しく説明されています。ざっくり言うと、状態遷移表を行列(これを「関係行列」といいます)とみなして、行列を掛け算することで求められます。

*2:A→B→A→Aのパターンが抜けていたので訂正。秋山さん、ありがとうございました!

*3:SとEが同一の状態であるとすれば、EからさらにAに入っていくことが可能です