複数条件の組み合わせによるテストケース数爆発と戦うPairwise(ペアワイズ)法とそれを支えるツール「PICT」

413件のシェア(そこそこ話題の記事)

新潟県長岡市からフルリモートでこんにちは。事業開発部の高野です。

みなさんテストしていますか?

私たち事業開発ではEC/CRMを支えるAPIプラットフォーム「prismatix」を開発しており、その中でも私はECの中核となる「注文」を扱うマイクロサービスを担当しています。この注文サービス、Amazonなどのショッピングサイトを利用したことがあれば少しわかるかもしれませんが、非常に多くの条件の組み合わせが発生します。

その中でも、今回は「ある複数の条件が組み合わさった時にクーポンが適用されるかどうか」についてテストする際、どのように条件の組合せ爆発を抑え、効率的なテストケースを作成していったのかを紹介します。

目次

複数条件の組合せ爆発

今回私が取り組んだのは、次のような条件の組み合わせについてのテストです。

下記の条件に合致した時、%引き、円引きするクーポンの適用結果を検証せよ

  • 対象の商品であること
  • 対象のカテゴリであること

※どちらか一方のみ指定されたクーポンならその条件のみで、両方指定されていたら両方の条件で判定する

具体的な条件の名前と取りうる値をまとめると、次のようになります。

  • 割引種別
    • %引き
    • 円引き
  • クーポン適用対象商品
    • 指定あり
    • 指定なし
  • クーポン適用対象カテゴリ
    • 指定あり
    • 指定なし
  • ショッピングカートの注文明細の商品
    • クーポン適用対象
    • クーポン適用対象外
  • ショッピングカートの注文明細のカテゴリ
    • クーポン適用対象
    • クーポン適用対象外
    • 指定なし

5つの条件で取りうる値がそれぞれ2つずつあるので、単純に全ての条件の組み合わせを網羅すると、2 * 2 * 2 * 2 * 3 = 48 ケースになります

全48ケース
割引種別 クーポン適用対象商品 クーポン適用対象カテゴリ ショッピングカートの注文明細の商品 ショッピングカートの注文明細のカテゴリ
%引き 指定あり 指定あり クーポン適用対象 クーポン適用対象
%引き 指定あり 指定あり クーポン適用対象 クーポン適用対象外
%引き 指定あり 指定あり クーポン適用対象 指定なし
%引き 指定あり 指定あり クーポン適用対象外 クーポン適用対象
%引き 指定あり 指定あり クーポン適用対象外 クーポン適用対象外
%引き 指定あり 指定あり クーポン適用対象外 指定なし
%引き 指定あり 指定なし クーポン適用対象 クーポン適用対象
%引き 指定あり 指定なし クーポン適用対象 クーポン適用対象外
%引き 指定あり 指定なし クーポン適用対象 指定なし
%引き 指定あり 指定なし クーポン適用対象外 クーポン適用対象
%引き 指定あり 指定なし クーポン適用対象外 クーポン適用対象外
%引き 指定あり 指定なし クーポン適用対象外 指定なし
%引き 指定なし 指定あり クーポン適用対象 クーポン適用対象
%引き 指定なし 指定あり クーポン適用対象 クーポン適用対象外
%引き 指定なし 指定あり クーポン適用対象 指定なし
%引き 指定なし 指定あり クーポン適用対象外 クーポン適用対象
%引き 指定なし 指定あり クーポン適用対象外 クーポン適用対象外
%引き 指定なし 指定あり クーポン適用対象外 指定なし
%引き 指定なし 指定なし クーポン適用対象 クーポン適用対象
%引き 指定なし 指定なし クーポン適用対象 クーポン適用対象外
%引き 指定なし 指定なし クーポン適用対象 指定なし
%引き 指定なし 指定なし クーポン適用対象外 クーポン適用対象
%引き 指定なし 指定なし クーポン適用対象外 クーポン適用対象外
%引き 指定なし 指定なし クーポン適用対象外 指定なし
円引き 指定あり 指定あり クーポン適用対象 クーポン適用対象
円引き 指定あり 指定あり クーポン適用対象 クーポン適用対象外
円引き 指定あり 指定あり クーポン適用対象 指定なし
円引き 指定あり 指定あり クーポン適用対象外 クーポン適用対象
円引き 指定あり 指定あり クーポン適用対象外 クーポン適用対象外
円引き 指定あり 指定あり クーポン適用対象外 指定なし
円引き 指定あり 指定なし クーポン適用対象 クーポン適用対象
円引き 指定あり 指定なし クーポン適用対象 クーポン適用対象外
円引き 指定あり 指定なし クーポン適用対象 指定なし
円引き 指定あり 指定なし クーポン適用対象外 クーポン適用対象
円引き 指定あり 指定なし クーポン適用対象外 クーポン適用対象外
円引き 指定あり 指定なし クーポン適用対象外 指定なし
円引き 指定なし 指定あり クーポン適用対象 クーポン適用対象
円引き 指定なし 指定あり クーポン適用対象 クーポン適用対象外
円引き 指定なし 指定あり クーポン適用対象 指定なし
円引き 指定なし 指定あり クーポン適用対象外 クーポン適用対象
円引き 指定なし 指定あり クーポン適用対象外 クーポン適用対象外
円引き 指定なし 指定あり クーポン適用対象外 指定なし
円引き 指定なし 指定なし クーポン適用対象 クーポン適用対象
円引き 指定なし 指定なし クーポン適用対象 クーポン適用対象外
円引き 指定なし 指定なし クーポン適用対象 指定なし
円引き 指定なし 指定なし クーポン適用対象外 クーポン適用対象
円引き 指定なし 指定なし クーポン適用対象外 クーポン適用対象外
円引き 指定なし 指定なし クーポン適用対象外 指定なし

これが「複数条件の組合せ爆発」です。まだ2桁程度なので頑張ればテストできなくもないですが、さらに条件が追加されたり、それぞれの条件が取りうる値が変わると、一気にテストケースが増えてしまいます。

組合せ爆発を抑えるPairwise(ペアワイズ)法

こういった複数条件を組み合わせたテストでは、いかに同じようなテストケースを削り、効率的な条件を残すかがポイントになります。そのための手法として有名な方法の1つがPairwise(ペアワイズ)法(またはオールペア法)です。

ペアワイズ法は、複数ある条件の2つを選んだ組み合わせが漏れなくカバーできるようにテストケースを絞り込み手法です。

例えば、3つの条件でそれぞれ取りうる値が2つあるケースを考えましょう。

  • A
    • A1
    • A2
  • B
    • B1
    • B2
  • C
    • C1
    • C2

単純に全ての組み合わせを作ると、2 * 2 * 2 = 8通りになります。

A B C
A1 B1 C1
A1 B1 C2
A1 B2 C1
A1 B2 C2
A2 B1 C1
A2 B1 C2
A2 B2 C1
A2 B2 C2

ここから、「AとB」「AとC」、「BとC」の組み合わせがそれぞれ漏れなくカバーできる組み合わせに絞ると、次のように4通りにまで絞り込めます。

A B C
A1 B1 C1
A1 B2 C2
A2 B1 C2
A2 B2 C1

ペアワイズ法を使うことで、効率的にテストケースを絞り込めることがわかったかと思います。

--- 2019/10/31 追記 ---

どうしてテストケースを絞り込んでも大丈夫なのか?という意見がSNSやはてブのコメントで見受けられたので、フォローアップエントリを書きました。こちらも合わせてご覧ください。

ペアワイズ法は本当に有効なのか?組み合わせテスト技法と上手に付き合う方法 | DevelopersIO

ペアワイズ法を支えるツール「PICT」

ペアワイズ法が有効なことはわかりましたが、この組み合わせをどうやって作れば良いでしょうか?条件の数が少なければ前述のように手作業でもやれないことはありませんが、現実の問題はもっと複雑ですので、到底無理でしょう。

そこで役に立つのが、ペアワイズ法のテストケースを生成してくれるツール「PICT」です。

microsoft/pict: Pairwise Independent Combinatorial Tool

PICT generates test cases and test configurations. With PICT, you can generate tests that are more effective than manually generated tests and in a fraction of the time required by hands-on test case design.

(太字箇所は引用者による装飾)

PICTはMicrosoftのResearchから生まれたCLIツールで、「モデルファイル」と呼ばれる組み合わせたい条件を記述したファイルをコマンドライン引数で与えると、その条件をペアワイズ法で組み合わせたテストケースを出力してくれます。

PICTについては、次のQiitaの記事が詳しいので参考にすると良いでしょう。

PICTを使うには、Windowsであればビルド済のexeファイルが上記GitHubリポジトリに記載されたURLより、ダウンロードできます。

The most recent pict.exe is available at http://www.pairwise.org/pict/win/pict.exe.

Windows以外の場合、Clangを使って自分でビルドする必要があります。私の場合はmacOSでしたので、Xcodeをインストールした後は、上記のQiitaの記事に記載された手順でインストールを行いました。

# リポジトリをクローン
$ git clone https://github.com/Microsoft/pict.git
$ cd pict/

$ make

# 成功したらpictコマンドのパスを通す
$ sudo install -m 0755 pict /usr/local/bin/pict 

なお、makeを実行しようとしたら、Xcodeのライセンスに同意していないという旨の警告が出たため、提示されたコマンドを実行してライセンス同意作業も行いました。

$ sudo xcodebuild -license

このコマンドについては、下記のQiitaの記事に詳しく記載されています。

テストケースの生成

それでは、PICTを使ってテストケースを生成してみましょう。

最初の一歩

まず、複数条件の組合せ爆発で紹介した各条件を下記のようにモデルファイルに記載し、test.txtファイルとして保存します。

割引種別: %引き, 円引き
クーポン適用対象商品: 指定あり, 指定なし
クーポン適用対象カテゴリ: 指定あり, 指定なし
商品: クーポン適用対象, クーポン適用対象外
カテゴリ: クーポン適用対象, クーポン適用対象外, 指定なし

そして、このtest.txtモデルファイルを使ってpictを実行すると、下記のように結果が出力されます。

$ pict test.txt
割引種別	クーポン適用対象商品	クーポン適用対象カテゴリ	商品	カテゴリ
円引き	指定あり	指定あり	クーポン適用対象	指定なし
%引き	指定なし	指定なし	クーポン適用対象外	指定なし
%引き	指定あり	指定なし	クーポン適用対象	クーポン適用対象外
%引き	指定なし	指定あり	クーポン適用対象外	クーポン適用対象
円引き	指定なし	指定あり	クーポン適用対象外	クーポン適用対象外
円引き	指定なし	指定なし	クーポン適用対象	クーポン適用対象
円引き	指定あり	指定なし	クーポン適用対象外	クーポン適用対象

出力結果はタブ文字(ASCII文字コード:0x09)区切りのTSV形式ですので、ターミナルからコピーしてExcel、Googleスプレッドシートなどに貼り付けると作業がしやすいでしょう。

PICTの結果をスプレッドシートに貼り付け

さて、出力されたテストケースを見ると、全部で7ケースにまで絞り込めています。全ての組み合わせは48でしたので、7/48≒15%程度までテストケース数を削減できました!

やったね!

……とは残念ながらなりません。

ありえないテストケースの考慮

生成されたテストケースの1つを見てみましょう。

割引種別 クーポン適用対象商品 クーポン適用対象カテゴリ 商品 カテゴリ
%引き 指定なし 指定なし クーポン適用対象外 指定なし

このテストケースでは、「クーポン適用対象商品」の指定はありませんが、「商品」がクーポン適用対象外という矛盾した状態になっています。つまり、このテストケースの検証は不可能です。

そして「クーポン適用カテゴリ」でも同様のテスト不能な組み合わせがあります。

割引種別 クーポン適用対象商品 クーポン適用対象カテゴリ 商品 カテゴリ
%引き 指定あり 指定なし クーポン適用対象 クーポン適用対象外

この2つのテストケースをテスト可能なものとするにはどうすればよいでしょうか。適用対象でも適用対象外でもないのですから、任意という値を「商品」、「カテゴリ」に新たに追加し、下記のようなテストケースを作れば、なんとかなりそうです。

割引種別 クーポン適用対象商品 クーポン適用対象カテゴリ 商品 カテゴリ
%引き 指定なし 指定なし 任意 指定なし
%引き 指定あり 指定なし クーポン適用対象 任意

この任意という値をpictのモデルファイルに反映させます。

割引種別: %引き, 円引き
クーポン適用対象商品: 指定あり, 指定なし
クーポン適用対象カテゴリ: 指定あり, 指定なし
商品: クーポン適用対象, クーポン適用対象外, 任意
#                                     ^^^^
カテゴリ: クーポン適用対象, クーポン適用対象外, 指定なし, 任意
#                                                 ^^^^

さて、このモデルファイルを元にpictを実行してみましょう。

$ pict test.txt
割引種別	クーポン適用対象商品	クーポン適用対象カテゴリ	商品	カテゴリ
円引き	指定あり	指定あり	クーポン適用対象	指定なし
%引き	指定なし	指定なし	クーポン適用対象	クーポン適用対象
円引き	指定なし	指定あり	任意	クーポン適用対象
円引き	指定あり	指定なし	クーポン適用対象	クーポン適用対象外
%引き	指定なし	指定あり	クーポン適用対象外	クーポン適用対象外
%引き	指定あり	指定なし	任意	任意
円引き	指定なし	指定なし	クーポン適用対象外	指定なし
円引き	指定なし	指定あり	クーポン適用対象	任意
%引き	指定あり	指定なし	クーポン適用対象外	クーポン適用対象
%引き	指定あり	指定あり	任意	指定なし
円引き	指定なし	指定なし	クーポン適用対象外	任意

おや、「クーポン適用対象商品」、「クーポン適用対象カテゴリ」が指定なしの時だけ任意であって欲しいのに、そうなっていないテストケースがあるようです。取り出して表にしてみましょう。

割引種別 クーポン適用対象商品 クーポン適用対象カテゴリ 商品 カテゴリ
%引き 指定なし 指定なし クーポン適用対象 クーポン適用対象
円引き 指定あり 指定なし クーポン適用対象 クーポン適用対象外
%引き 指定なし 指定あり クーポン適用対象外 クーポン適用対象外
%引き 指定あり 指定なし 任意 任意
円引き 指定なし 指定あり クーポン適用対象 任意
%引き 指定あり 指定なし クーポン適用対象外 クーポン適用対象
%引き 指定あり 指定あり 任意 指定なし
円引き 指定なし 指定なし クーポン適用対象外 任意

せっかくモデルファイルを変更しましたが、このままでは使い物になりそうにありません。困りましたね。

テストケースの制約

こんな事態に対処するため、pictのモデルファイルにはテストケースの条件の組み合わせを制御する方法として制約が用意されています。今回のケースでは

  • 指定なしの時は任意のみ
    • ただし、「クーポン適用対象カテゴリ」は任意の他に指定なしも可
  • 指定ありの時は任意以外

を組み合わせるように指定すれば良いでしょう。この制約をモデルファイルに加えてみます。

割引種別: %引き, 円引き
クーポン適用対象商品: 指定あり, 指定なし
クーポン適用対象カテゴリ: 指定あり, 指定なし
商品: クーポン適用対象, クーポン適用対象外, 任意
カテゴリ: クーポン適用対象, クーポン適用対象外, 指定なし, 任意

# 追加した制約
if [クーポン適用対象商品] = "指定なし" then [商品] = "任意";
if [クーポン適用対象商品] = "指定あり" then [商品] <> "任意";
if [クーポン適用対象カテゴリ] = "指定なし" then [カテゴリ] in {"指定なし", "任意"};
if [クーポン適用対象カテゴリ] = "指定あり" then [カテゴリ] <> "任意";

制約はif [条件名] = "値" then [条件名] = "値";という形式で指定します。

ifで指定する条件には=以外に不一致を表す<>やSQLのIN句のようにin {取りうる条件値...}なども指定できます。また、andorなど論理演算子も使えるため、複数の条件の組み合わせも可能です。

thenで指定する値もifと同様に一致、不一致、取りうる値などを指定できます。詳しくはPICTのドキュメントを参照してください。

制約を指定したモデルファイルから生成したテストケースは下記の通りです。

割引種別 クーポン適用対象商品 クーポン適用対象カテゴリ 商品 カテゴリ
%引き 指定あり 指定あり クーポン適用対象 指定なし
円引き 指定なし 指定あり 任意 クーポン適用対象外
円引き 指定あり 指定あり クーポン適用対象外 クーポン適用対象
円引き 指定あり 指定なし クーポン適用対象 任意
%引き 指定あり 指定あり クーポン適用対象 クーポン適用対象外
%引き 指定あり 指定なし クーポン適用対象外 指定なし
円引き 指定あり 指定あり クーポン適用対象外 クーポン適用対象外
%引き 指定なし 指定なし 任意 任意
%引き 指定なし 指定あり 任意 クーポン適用対象
円引き 指定あり 指定あり クーポン適用対象 クーポン適用対象
%引き 指定あり 指定なし クーポン適用対象外 任意
円引き 指定なし 指定なし 任意 指定なし

これでようやくテスト不能なテストケースがなくなりました。テストケース数も12ですので、12/48=1/4まで減らすことができました。

テストケースの整形

テスト条件の組み合わせができたところで、今度は実際にテストしやすいように整形していきます。まずはpictの結果を前述のようにスプレッドシートに貼り付けて、編集しやすくしましょう。

次は並び替えなどを行うため、「フィルタ」機能を使います。

テストケースにフィルタを適用

フィルタを適用したら、「カテゴリ」→「商品」→「クーポン適用対象カテゴリ」→「クーポン適用対象商品」の順番で各条件のヘッダから並び替えを行います。

ヘッダから順に条件をソート

すると、「クーポン適用対象商品」、「クーポン適用対象カテゴリ」、「商品」、「カテゴリ」の順にテストケースが並びます。

ソートされたテストケース

フィルタで並び変えるのはここまでです。あとは手動で扱いやすいようにテストケースを並び変えていきましょう。

今回は「クーポン適用対象商品」、「クーポン適用対象カテゴリ」について

  • 一方だけ指定されるケース
  • 両方指定もしくは指定なしのケース

の2つに大きく分けていきます。この時、枠線やセル背景色などで装飾するのもよいでしょう。

手動でテストケースを並びかえる

ここまでやったところで、「クーポン適用対象商品」、「クーポン適用対象カテゴリ」の一方のみ指定されるまとまりに「クーポン適用対象カテゴリ」が指定ありで「カテゴリ」が指定なしのケースが漏れていることに気づきましたので、手動で追加します。

不足していたテストケースを追加

あとは、今回は%引き、円引きはどの組み合わせでも計算方法は一緒なので、前述の2つのまとまりごとに同じ値を使うようにしてしまいましょう。

割引種別を揃える

これでテストケースの作成は完了です!

このあとは、それぞれのテストケースについて期待結果を検討し、実際のテストシナリオへと落とし込んでいき、実際のテストを行う準備に入ります。

まとめ

複数の条件を元にしたテストでは、その組み合わせが膨大になること。そのテストケースを絞り込むにはペアワイズ法が有効であること、ペアワイズ法を利用するためのツール「PICT」があることを紹介しました。

ただ、今回の方法は事前にテストのパラメータとなる各種の「条件」がわかっていなければなりません。この条件を見いだすのは容易ではないので、もっと俯瞰した視点での「テスト設計」のスキル、プロセスを身につけなければなりません。

そのためにも、PICTのようなツールを最大限活用することで楽をして、より創造的な仕事に取り組んでいきましょう。