組み合わせテストの直行表とオールペア法について、最近気になって調べた結果を記載します。


直交表について

(株)日科技研:直交表とは(実験計画法)|製品案内 には以下記載されています。

直交表とは,任意の2因子(列)について,その水準のすべての組合せが同数回ずつ現れるという性質をもつ実験のための割り付け表です.

直交表には,いろいろなものがありますが,これを表すのに一般にLN(PK)という記号を用います.Lは直交表を表す記号(LATIN SQUAREに由来)であり,Nは実験の大きさ(直交表の行数),Pは因子の水準数Kは直交表の列数を示しています.関係式は,N-1/P-1=Kとなります.

膨大な直交表のライブラリを掲載している3つのサイト | 組み合わせテストケース生成ツール 「PictMaster」 とソフトウェアテストの話題 からリンクされているサイトを見た感じ、どちらかというと直交表のテンプレートにあうように、テストの因子数、水準を調整するのかなと思いました。


オールペア法について

Pairwise Testing - Research Papersオールペア法の参考文献の一覧があります。
1因子もしくは、2因子の組み合わせでのバグが80%-90%だという経験則に基づき、テストケースを生成する手法です。

  • N-wise testing
    オールペア法(ペアワイズ法)は2因子の組み合わせ網羅のテストケースになります。1因子網羅の組み合わせ網羅のテストケースはone wise といい、N因子網羅のテストをN-wise testing呼ぶようです。 PICTはN因子の組み合わせ網羅のテストケース生成にも対応しているので、一部の組み合わせのみ厚くテストを実施するという用途にも使用できます。PICTの使用方法は以下のQiita記事にわかりやすく記載されています。

  • One wise
    1因子の組み合わせ網羅のテストケースを生成してくれる JavaScript ライブラリがあります。
    テストケース数は、因子の中でもっとも要素数の多い因子の要素すうに従って生成されます。

  • 有即と無即、デシジョンテーブルと、オールペア法の使い分け
    有即と無即という概念があり、それでデシジョンテーブルと、オールペア法を使い分けたほうが良さそうです。
    以下のスライドが参考になりました。


allpairspy をインストールして使ってみる

allpairspyという、オールペア法のテストケースが生成できる Python のライブラリがあります。

allpairspy をインストールして使ってみます。

インストール

!pip install allpairspy

Collecting allpairspy
  Downloading https://files.pythonhosted.org/packages/58/23/7890aa2f8064c14462163cdf707828fbad1c21a26b3bacd30577042417fb/allpairspy-2.5.0-py2.py3-none-any.whl
Requirement already satisfied: six<2.0.0,>=1.10.0 in /Users/kensakurai/Programing/Bitbucket/monotalk_blogs/contents/jupyter/.env_jupyter/lib/python3.7/site-packages (from allpairspy) (1.12.0)
Installing collected packages: allpairspy
Successfully installed allpairspy-2.5.0

Example の実行

allpairspy · PyPI記載されているサンプルプログラムを実行します。
テストケース数を数えるため、インデックス番号に1を足しています。

from allpairspy import AllPairs

parameters = [
    ["Brand X", "Brand Y"],
    ["98", "NT", "2000", "XP"],
    ["Internal", "Modem"],
    ["Salaried", "Hourly", "Part-Time", "Contr."],
    [6, 10, 15, 30, 60],
]

print("PAIRWISE:")
for i, pairs in enumerate(AllPairs(parameters)):
    print("{:2d}: {}".format(i + 1, pairs))

PAIRWISE:
 1: ['Brand X', '98', 'Internal', 'Salaried', 6]
 2: ['Brand Y', 'NT', 'Modem', 'Hourly', 6]
 3: ['Brand Y', '2000', 'Internal', 'Part-Time', 10]
 4: ['Brand X', 'XP', 'Modem', 'Contr.', 10]
 5: ['Brand X', '2000', 'Modem', 'Part-Time', 15]
 6: ['Brand Y', 'XP', 'Internal', 'Hourly', 15]
 7: ['Brand Y', '98', 'Modem', 'Salaried', 30]
 8: ['Brand X', 'NT', 'Internal', 'Contr.', 30]
 9: ['Brand X', '98', 'Internal', 'Hourly', 60]
10: ['Brand Y', '2000', 'Modem', 'Contr.', 60]
11: ['Brand Y', 'NT', 'Modem', 'Salaried', 60]
12: ['Brand Y', 'XP', 'Modem', 'Part-Time', 60]
13: ['Brand Y', '2000', 'Modem', 'Hourly', 30]
14: ['Brand Y', '98', 'Modem', 'Contr.', 15]
15: ['Brand Y', 'XP', 'Modem', 'Salaried', 15]
16: ['Brand Y', 'NT', 'Modem', 'Part-Time', 15]
17: ['Brand Y', 'XP', 'Modem', 'Part-Time', 30]
18: ['Brand Y', '98', 'Modem', 'Part-Time', 6]
19: ['Brand Y', '2000', 'Modem', 'Salaried', 6]
20: ['Brand Y', '98', 'Modem', 'Salaried', 10]
21: ['Brand Y', 'XP', 'Modem', 'Contr.', 6]
22: ['Brand Y', 'NT', 'Modem', 'Hourly', 10]

直積 (全組み合わせ)とのテストケース数の比較

itertools.product直積 (全組み合わせ) を作成できます。

import itertools

a = ["Brand X", "Brand Y"]
b = ["98", "NT", "2000", "XP"]
c = ["Internal", "Modem"]
d = ["Salaried", "Hourly", "Part-Time", "Contr."]
e = [6, 10, 15, 30, 60]

print("PRODUCT:")
for i, pairs in enumerate(itertools.product(a, b,c,d,e)):
    print("{:2d}: {}".format(i + 1, pairs))

PRODUCT:
 1: ('Brand X', '98', 'Internal', 'Salaried', 6)
 2: ('Brand X', '98', 'Internal', 'Salaried', 10)
 3: ('Brand X', '98', 'Internal', 'Salaried', 15)
 4: ('Brand X', '98', 'Internal', 'Salaried', 30)
 5: ('Brand X', '98', 'Internal', 'Salaried', 60)
 6: ('Brand X', '98', 'Internal', 'Hourly', 6)
 7: ('Brand X', '98', 'Internal', 'Hourly', 10)
 8: ('Brand X', '98', 'Internal', 'Hourly', 15)
 9: ('Brand X', '98', 'Internal', 'Hourly', 30)
10: ('Brand X', '98', 'Internal', 'Hourly', 60)
11: ('Brand X', '98', 'Internal', 'Part-Time', 6)
12: ('Brand X', '98', 'Internal', 'Part-Time', 10)
13: ('Brand X', '98', 'Internal', 'Part-Time', 15)
14: ('Brand X', '98', 'Internal', 'Part-Time', 30)
15: ('Brand X', '98', 'Internal', 'Part-Time', 60)
16: ('Brand X', '98', 'Internal', 'Contr.', 6)
17: ('Brand X', '98', 'Internal', 'Contr.', 10)
18: ('Brand X', '98', 'Internal', 'Contr.', 15)
19: ('Brand X', '98', 'Internal', 'Contr.', 30)
20: ('Brand X', '98', 'Internal', 'Contr.', 60)
21: ('Brand X', '98', 'Modem', 'Salaried', 6)
22: ('Brand X', '98', 'Modem', 'Salaried', 10)
23: ('Brand X', '98', 'Modem', 'Salaried', 15)
24: ('Brand X', '98', 'Modem', 'Salaried', 30)
25: ('Brand X', '98', 'Modem', 'Salaried', 60)
26: ('Brand X', '98', 'Modem', 'Hourly', 6)
27: ('Brand X', '98', 'Modem', 'Hourly', 10)
28: ('Brand X', '98', 'Modem', 'Hourly', 15)
29: ('Brand X', '98', 'Modem', 'Hourly', 30)
30: ('Brand X', '98', 'Modem', 'Hourly', 60)
31: ('Brand X', '98', 'Modem', 'Part-Time', 6)
32: ('Brand X', '98', 'Modem', 'Part-Time', 10)
33: ('Brand X', '98', 'Modem', 'Part-Time', 15)
34: ('Brand X', '98', 'Modem', 'Part-Time', 30)
35: ('Brand X', '98', 'Modem', 'Part-Time', 60)
36: ('Brand X', '98', 'Modem', 'Contr.', 6)
37: ('Brand X', '98', 'Modem', 'Contr.', 10)
38: ('Brand X', '98', 'Modem', 'Contr.', 15)
39: ('Brand X', '98', 'Modem', 'Contr.', 30)
40: ('Brand X', '98', 'Modem', 'Contr.', 60)
41: ('Brand X', 'NT', 'Internal', 'Salaried', 6)
42: ('Brand X', 'NT', 'Internal', 'Salaried', 10)
43: ('Brand X', 'NT', 'Internal', 'Salaried', 15)
44: ('Brand X', 'NT', 'Internal', 'Salaried', 30)
45: ('Brand X', 'NT', 'Internal', 'Salaried', 60)
46: ('Brand X', 'NT', 'Internal', 'Hourly', 6)
47: ('Brand X', 'NT', 'Internal', 'Hourly', 10)
48: ('Brand X', 'NT', 'Internal', 'Hourly', 15)
49: ('Brand X', 'NT', 'Internal', 'Hourly', 30)
50: ('Brand X', 'NT', 'Internal', 'Hourly', 60)
51: ('Brand X', 'NT', 'Internal', 'Part-Time', 6)
52: ('Brand X', 'NT', 'Internal', 'Part-Time', 10)
53: ('Brand X', 'NT', 'Internal', 'Part-Time', 15)
54: ('Brand X', 'NT', 'Internal', 'Part-Time', 30)
55: ('Brand X', 'NT', 'Internal', 'Part-Time', 60)
56: ('Brand X', 'NT', 'Internal', 'Contr.', 6)
57: ('Brand X', 'NT', 'Internal', 'Contr.', 10)
58: ('Brand X', 'NT', 'Internal', 'Contr.', 15)
59: ('Brand X', 'NT', 'Internal', 'Contr.', 30)
60: ('Brand X', 'NT', 'Internal', 'Contr.', 60)
61: ('Brand X', 'NT', 'Modem', 'Salaried', 6)
62: ('Brand X', 'NT', 'Modem', 'Salaried', 10)
63: ('Brand X', 'NT', 'Modem', 'Salaried', 15)
64: ('Brand X', 'NT', 'Modem', 'Salaried', 30)
65: ('Brand X', 'NT', 'Modem', 'Salaried', 60)
66: ('Brand X', 'NT', 'Modem', 'Hourly', 6)
67: ('Brand X', 'NT', 'Modem', 'Hourly', 10)
68: ('Brand X', 'NT', 'Modem', 'Hourly', 15)
69: ('Brand X', 'NT', 'Modem', 'Hourly', 30)
70: ('Brand X', 'NT', 'Modem', 'Hourly', 60)
71: ('Brand X', 'NT', 'Modem', 'Part-Time', 6)
72: ('Brand X', 'NT', 'Modem', 'Part-Time', 10)
73: ('Brand X', 'NT', 'Modem', 'Part-Time', 15)
74: ('Brand X', 'NT', 'Modem', 'Part-Time', 30)
75: ('Brand X', 'NT', 'Modem', 'Part-Time', 60)
76: ('Brand X', 'NT', 'Modem', 'Contr.', 6)
77: ('Brand X', 'NT', 'Modem', 'Contr.', 10)
78: ('Brand X', 'NT', 'Modem', 'Contr.', 15)
79: ('Brand X', 'NT', 'Modem', 'Contr.', 30)
80: ('Brand X', 'NT', 'Modem', 'Contr.', 60)
81: ('Brand X', '2000', 'Internal', 'Salaried', 6)
82: ('Brand X', '2000', 'Internal', 'Salaried', 10)
83: ('Brand X', '2000', 'Internal', 'Salaried', 15)
84: ('Brand X', '2000', 'Internal', 'Salaried', 30)
85: ('Brand X', '2000', 'Internal', 'Salaried', 60)
86: ('Brand X', '2000', 'Internal', 'Hourly', 6)
87: ('Brand X', '2000', 'Internal', 'Hourly', 10)
88: ('Brand X', '2000', 'Internal', 'Hourly', 15)
89: ('Brand X', '2000', 'Internal', 'Hourly', 30)
90: ('Brand X', '2000', 'Internal', 'Hourly', 60)
91: ('Brand X', '2000', 'Internal', 'Part-Time', 6)
92: ('Brand X', '2000', 'Internal', 'Part-Time', 10)
93: ('Brand X', '2000', 'Internal', 'Part-Time', 15)
94: ('Brand X', '2000', 'Internal', 'Part-Time', 30)
95: ('Brand X', '2000', 'Internal', 'Part-Time', 60)
96: ('Brand X', '2000', 'Internal', 'Contr.', 6)
97: ('Brand X', '2000', 'Internal', 'Contr.', 10)
98: ('Brand X', '2000', 'Internal', 'Contr.', 15)
99: ('Brand X', '2000', 'Internal', 'Contr.', 30)
100: ('Brand X', '2000', 'Internal', 'Contr.', 60)
101: ('Brand X', '2000', 'Modem', 'Salaried', 6)
102: ('Brand X', '2000', 'Modem', 'Salaried', 10)
103: ('Brand X', '2000', 'Modem', 'Salaried', 15)
104: ('Brand X', '2000', 'Modem', 'Salaried', 30)
105: ('Brand X', '2000', 'Modem', 'Salaried', 60)
106: ('Brand X', '2000', 'Modem', 'Hourly', 6)
107: ('Brand X', '2000', 'Modem', 'Hourly', 10)
108: ('Brand X', '2000', 'Modem', 'Hourly', 15)
109: ('Brand X', '2000', 'Modem', 'Hourly', 30)
110: ('Brand X', '2000', 'Modem', 'Hourly', 60)
111: ('Brand X', '2000', 'Modem', 'Part-Time', 6)
112: ('Brand X', '2000', 'Modem', 'Part-Time', 10)
113: ('Brand X', '2000', 'Modem', 'Part-Time', 15)
114: ('Brand X', '2000', 'Modem', 'Part-Time', 30)
115: ('Brand X', '2000', 'Modem', 'Part-Time', 60)
116: ('Brand X', '2000', 'Modem', 'Contr.', 6)
117: ('Brand X', '2000', 'Modem', 'Contr.', 10)
118: ('Brand X', '2000', 'Modem', 'Contr.', 15)
119: ('Brand X', '2000', 'Modem', 'Contr.', 30)
120: ('Brand X', '2000', 'Modem', 'Contr.', 60)
121: ('Brand X', 'XP', 'Internal', 'Salaried', 6)
122: ('Brand X', 'XP', 'Internal', 'Salaried', 10)
123: ('Brand X', 'XP', 'Internal', 'Salaried', 15)
124: ('Brand X', 'XP', 'Internal', 'Salaried', 30)
125: ('Brand X', 'XP', 'Internal', 'Salaried', 60)
126: ('Brand X', 'XP', 'Internal', 'Hourly', 6)
127: ('Brand X', 'XP', 'Internal', 'Hourly', 10)
128: ('Brand X', 'XP', 'Internal', 'Hourly', 15)
129: ('Brand X', 'XP', 'Internal', 'Hourly', 30)
130: ('Brand X', 'XP', 'Internal', 'Hourly', 60)
131: ('Brand X', 'XP', 'Internal', 'Part-Time', 6)
132: ('Brand X', 'XP', 'Internal', 'Part-Time', 10)
133: ('Brand X', 'XP', 'Internal', 'Part-Time', 15)
134: ('Brand X', 'XP', 'Internal', 'Part-Time', 30)
135: ('Brand X', 'XP', 'Internal', 'Part-Time', 60)
136: ('Brand X', 'XP', 'Internal', 'Contr.', 6)
137: ('Brand X', 'XP', 'Internal', 'Contr.', 10)
138: ('Brand X', 'XP', 'Internal', 'Contr.', 15)
139: ('Brand X', 'XP', 'Internal', 'Contr.', 30)
140: ('Brand X', 'XP', 'Internal', 'Contr.', 60)
141: ('Brand X', 'XP', 'Modem', 'Salaried', 6)
142: ('Brand X', 'XP', 'Modem', 'Salaried', 10)
143: ('Brand X', 'XP', 'Modem', 'Salaried', 15)
144: ('Brand X', 'XP', 'Modem', 'Salaried', 30)
145: ('Brand X', 'XP', 'Modem', 'Salaried', 60)
146: ('Brand X', 'XP', 'Modem', 'Hourly', 6)
147: ('Brand X', 'XP', 'Modem', 'Hourly', 10)
148: ('Brand X', 'XP', 'Modem', 'Hourly', 15)
149: ('Brand X', 'XP', 'Modem', 'Hourly', 30)
150: ('Brand X', 'XP', 'Modem', 'Hourly', 60)
151: ('Brand X', 'XP', 'Modem', 'Part-Time', 6)
152: ('Brand X', 'XP', 'Modem', 'Part-Time', 10)
153: ('Brand X', 'XP', 'Modem', 'Part-Time', 15)
154: ('Brand X', 'XP', 'Modem', 'Part-Time', 30)
155: ('Brand X', 'XP', 'Modem', 'Part-Time', 60)
156: ('Brand X', 'XP', 'Modem', 'Contr.', 6)
157: ('Brand X', 'XP', 'Modem', 'Contr.', 10)
158: ('Brand X', 'XP', 'Modem', 'Contr.', 15)
159: ('Brand X', 'XP', 'Modem', 'Contr.', 30)
160: ('Brand X', 'XP', 'Modem', 'Contr.', 60)
161: ('Brand Y', '98', 'Internal', 'Salaried', 6)
162: ('Brand Y', '98', 'Internal', 'Salaried', 10)
163: ('Brand Y', '98', 'Internal', 'Salaried', 15)
164: ('Brand Y', '98', 'Internal', 'Salaried', 30)
165: ('Brand Y', '98', 'Internal', 'Salaried', 60)
166: ('Brand Y', '98', 'Internal', 'Hourly', 6)
167: ('Brand Y', '98', 'Internal', 'Hourly', 10)
168: ('Brand Y', '98', 'Internal', 'Hourly', 15)
169: ('Brand Y', '98', 'Internal', 'Hourly', 30)
170: ('Brand Y', '98', 'Internal', 'Hourly', 60)
171: ('Brand Y', '98', 'Internal', 'Part-Time', 6)
172: ('Brand Y', '98', 'Internal', 'Part-Time', 10)
173: ('Brand Y', '98', 'Internal', 'Part-Time', 15)
174: ('Brand Y', '98', 'Internal', 'Part-Time', 30)
175: ('Brand Y', '98', 'Internal', 'Part-Time', 60)
176: ('Brand Y', '98', 'Internal', 'Contr.', 6)
177: ('Brand Y', '98', 'Internal', 'Contr.', 10)
178: ('Brand Y', '98', 'Internal', 'Contr.', 15)
179: ('Brand Y', '98', 'Internal', 'Contr.', 30)
180: ('Brand Y', '98', 'Internal', 'Contr.', 60)
181: ('Brand Y', '98', 'Modem', 'Salaried', 6)
182: ('Brand Y', '98', 'Modem', 'Salaried', 10)
183: ('Brand Y', '98', 'Modem', 'Salaried', 15)
184: ('Brand Y', '98', 'Modem', 'Salaried', 30)
185: ('Brand Y', '98', 'Modem', 'Salaried', 60)
186: ('Brand Y', '98', 'Modem', 'Hourly', 6)
187: ('Brand Y', '98', 'Modem', 'Hourly', 10)
188: ('Brand Y', '98', 'Modem', 'Hourly', 15)
189: ('Brand Y', '98', 'Modem', 'Hourly', 30)
190: ('Brand Y', '98', 'Modem', 'Hourly', 60)
191: ('Brand Y', '98', 'Modem', 'Part-Time', 6)
192: ('Brand Y', '98', 'Modem', 'Part-Time', 10)
193: ('Brand Y', '98', 'Modem', 'Part-Time', 15)
194: ('Brand Y', '98', 'Modem', 'Part-Time', 30)
195: ('Brand Y', '98', 'Modem', 'Part-Time', 60)
196: ('Brand Y', '98', 'Modem', 'Contr.', 6)
197: ('Brand Y', '98', 'Modem', 'Contr.', 10)
198: ('Brand Y', '98', 'Modem', 'Contr.', 15)
199: ('Brand Y', '98', 'Modem', 'Contr.', 30)
200: ('Brand Y', '98', 'Modem', 'Contr.', 60)
201: ('Brand Y', 'NT', 'Internal', 'Salaried', 6)
202: ('Brand Y', 'NT', 'Internal', 'Salaried', 10)
203: ('Brand Y', 'NT', 'Internal', 'Salaried', 15)
204: ('Brand Y', 'NT', 'Internal', 'Salaried', 30)
205: ('Brand Y', 'NT', 'Internal', 'Salaried', 60)
206: ('Brand Y', 'NT', 'Internal', 'Hourly', 6)
207: ('Brand Y', 'NT', 'Internal', 'Hourly', 10)
208: ('Brand Y', 'NT', 'Internal', 'Hourly', 15)
209: ('Brand Y', 'NT', 'Internal', 'Hourly', 30)
210: ('Brand Y', 'NT', 'Internal', 'Hourly', 60)
211: ('Brand Y', 'NT', 'Internal', 'Part-Time', 6)
212: ('Brand Y', 'NT', 'Internal', 'Part-Time', 10)
213: ('Brand Y', 'NT', 'Internal', 'Part-Time', 15)
214: ('Brand Y', 'NT', 'Internal', 'Part-Time', 30)
215: ('Brand Y', 'NT', 'Internal', 'Part-Time', 60)
216: ('Brand Y', 'NT', 'Internal', 'Contr.', 6)
217: ('Brand Y', 'NT', 'Internal', 'Contr.', 10)
218: ('Brand Y', 'NT', 'Internal', 'Contr.', 15)
219: ('Brand Y', 'NT', 'Internal', 'Contr.', 30)
220: ('Brand Y', 'NT', 'Internal', 'Contr.', 60)
221: ('Brand Y', 'NT', 'Modem', 'Salaried', 6)
222: ('Brand Y', 'NT', 'Modem', 'Salaried', 10)
223: ('Brand Y', 'NT', 'Modem', 'Salaried', 15)
224: ('Brand Y', 'NT', 'Modem', 'Salaried', 30)
225: ('Brand Y', 'NT', 'Modem', 'Salaried', 60)
226: ('Brand Y', 'NT', 'Modem', 'Hourly', 6)
227: ('Brand Y', 'NT', 'Modem', 'Hourly', 10)
228: ('Brand Y', 'NT', 'Modem', 'Hourly', 15)
229: ('Brand Y', 'NT', 'Modem', 'Hourly', 30)
230: ('Brand Y', 'NT', 'Modem', 'Hourly', 60)
231: ('Brand Y', 'NT', 'Modem', 'Part-Time', 6)
232: ('Brand Y', 'NT', 'Modem', 'Part-Time', 10)
233: ('Brand Y', 'NT', 'Modem', 'Part-Time', 15)
234: ('Brand Y', 'NT', 'Modem', 'Part-Time', 30)
235: ('Brand Y', 'NT', 'Modem', 'Part-Time', 60)
236: ('Brand Y', 'NT', 'Modem', 'Contr.', 6)
237: ('Brand Y', 'NT', 'Modem', 'Contr.', 10)
238: ('Brand Y', 'NT', 'Modem', 'Contr.', 15)
239: ('Brand Y', 'NT', 'Modem', 'Contr.', 30)
240: ('Brand Y', 'NT', 'Modem', 'Contr.', 60)
241: ('Brand Y', '2000', 'Internal', 'Salaried', 6)
242: ('Brand Y', '2000', 'Internal', 'Salaried', 10)
243: ('Brand Y', '2000', 'Internal', 'Salaried', 15)
244: ('Brand Y', '2000', 'Internal', 'Salaried', 30)
245: ('Brand Y', '2000', 'Internal', 'Salaried', 60)
246: ('Brand Y', '2000', 'Internal', 'Hourly', 6)
247: ('Brand Y', '2000', 'Internal', 'Hourly', 10)
248: ('Brand Y', '2000', 'Internal', 'Hourly', 15)
249: ('Brand Y', '2000', 'Internal', 'Hourly', 30)
250: ('Brand Y', '2000', 'Internal', 'Hourly', 60)
251: ('Brand Y', '2000', 'Internal', 'Part-Time', 6)
252: ('Brand Y', '2000', 'Internal', 'Part-Time', 10)
253: ('Brand Y', '2000', 'Internal', 'Part-Time', 15)
254: ('Brand Y', '2000', 'Internal', 'Part-Time', 30)
255: ('Brand Y', '2000', 'Internal', 'Part-Time', 60)
256: ('Brand Y', '2000', 'Internal', 'Contr.', 6)
257: ('Brand Y', '2000', 'Internal', 'Contr.', 10)
258: ('Brand Y', '2000', 'Internal', 'Contr.', 15)
259: ('Brand Y', '2000', 'Internal', 'Contr.', 30)
260: ('Brand Y', '2000', 'Internal', 'Contr.', 60)
261: ('Brand Y', '2000', 'Modem', 'Salaried', 6)
262: ('Brand Y', '2000', 'Modem', 'Salaried', 10)
263: ('Brand Y', '2000', 'Modem', 'Salaried', 15)
264: ('Brand Y', '2000', 'Modem', 'Salaried', 30)
265: ('Brand Y', '2000', 'Modem', 'Salaried', 60)
266: ('Brand Y', '2000', 'Modem', 'Hourly', 6)
267: ('Brand Y', '2000', 'Modem', 'Hourly', 10)
268: ('Brand Y', '2000', 'Modem', 'Hourly', 15)
269: ('Brand Y', '2000', 'Modem', 'Hourly', 30)
270: ('Brand Y', '2000', 'Modem', 'Hourly', 60)
271: ('Brand Y', '2000', 'Modem', 'Part-Time', 6)
272: ('Brand Y', '2000', 'Modem', 'Part-Time', 10)
273: ('Brand Y', '2000', 'Modem', 'Part-Time', 15)
274: ('Brand Y', '2000', 'Modem', 'Part-Time', 30)
275: ('Brand Y', '2000', 'Modem', 'Part-Time', 60)
276: ('Brand Y', '2000', 'Modem', 'Contr.', 6)
277: ('Brand Y', '2000', 'Modem', 'Contr.', 10)
278: ('Brand Y', '2000', 'Modem', 'Contr.', 15)
279: ('Brand Y', '2000', 'Modem', 'Contr.', 30)
280: ('Brand Y', '2000', 'Modem', 'Contr.', 60)
281: ('Brand Y', 'XP', 'Internal', 'Salaried', 6)
282: ('Brand Y', 'XP', 'Internal', 'Salaried', 10)
283: ('Brand Y', 'XP', 'Internal', 'Salaried', 15)
284: ('Brand Y', 'XP', 'Internal', 'Salaried', 30)
285: ('Brand Y', 'XP', 'Internal', 'Salaried', 60)
286: ('Brand Y', 'XP', 'Internal', 'Hourly', 6)
287: ('Brand Y', 'XP', 'Internal', 'Hourly', 10)
288: ('Brand Y', 'XP', 'Internal', 'Hourly', 15)
289: ('Brand Y', 'XP', 'Internal', 'Hourly', 30)
290: ('Brand Y', 'XP', 'Internal', 'Hourly', 60)
291: ('Brand Y', 'XP', 'Internal', 'Part-Time', 6)
292: ('Brand Y', 'XP', 'Internal', 'Part-Time', 10)
293: ('Brand Y', 'XP', 'Internal', 'Part-Time', 15)
294: ('Brand Y', 'XP', 'Internal', 'Part-Time', 30)
295: ('Brand Y', 'XP', 'Internal', 'Part-Time', 60)
296: ('Brand Y', 'XP', 'Internal', 'Contr.', 6)
297: ('Brand Y', 'XP', 'Internal', 'Contr.', 10)
298: ('Brand Y', 'XP', 'Internal', 'Contr.', 15)
299: ('Brand Y', 'XP', 'Internal', 'Contr.', 30)
300: ('Brand Y', 'XP', 'Internal', 'Contr.', 60)
301: ('Brand Y', 'XP', 'Modem', 'Salaried', 6)
302: ('Brand Y', 'XP', 'Modem', 'Salaried', 10)
303: ('Brand Y', 'XP', 'Modem', 'Salaried', 15)
304: ('Brand Y', 'XP', 'Modem', 'Salaried', 30)
305: ('Brand Y', 'XP', 'Modem', 'Salaried', 60)
306: ('Brand Y', 'XP', 'Modem', 'Hourly', 6)
307: ('Brand Y', 'XP', 'Modem', 'Hourly', 10)
308: ('Brand Y', 'XP', 'Modem', 'Hourly', 15)
309: ('Brand Y', 'XP', 'Modem', 'Hourly', 30)
310: ('Brand Y', 'XP', 'Modem', 'Hourly', 60)
311: ('Brand Y', 'XP', 'Modem', 'Part-Time', 6)
312: ('Brand Y', 'XP', 'Modem', 'Part-Time', 10)
313: ('Brand Y', 'XP', 'Modem', 'Part-Time', 15)
314: ('Brand Y', 'XP', 'Modem', 'Part-Time', 30)
315: ('Brand Y', 'XP', 'Modem', 'Part-Time', 60)
316: ('Brand Y', 'XP', 'Modem', 'Contr.', 6)
317: ('Brand Y', 'XP', 'Modem', 'Contr.', 10)
318: ('Brand Y', 'XP', 'Modem', 'Contr.', 15)
319: ('Brand Y', 'XP', 'Modem', 'Contr.', 30)
320: ('Brand Y', 'XP', 'Modem', 'Contr.', 60)
  • 削減テストケース数と、バグ検出率
    全組み合わせでのテストケースが320、オールペア法でのテストケース数が22なので、298ケースが削減できることになります。
    これでどれくらいのバグが検出できるかというと、以下、基幹システムにおけるテスト十分性の確保いうPDF文書の引用です。
    1因子単独、2因子の網羅で 80%-100% のバグの検出ができるらしいです。

    D. Richard Kuhn[22]は,1 因子単独および 2 個の因子間の組み合わせで発生するバグが,全体の 7 ~ 9 割を占めると報告している.日本ユニシスの基幹システムで稼働後に発生したバグ(障害)を分析したところ,図 3 に示す通り 1 因子に起因する障害が 38%~ 65%,これに 2 因子の組み合わせで発生した障害を加えると,全体の 79%~ 100%を占めており,高い効果が見込めることが判明した.

  • 1因子単独、2因子の網羅で検出できないバグをどう検出するか
    個人的には以下が浮かびました。

    • リスクベースの考えで、リスクの高い因子の組み合わせについては、全網羅テストを実施する。
    • ホワイトボックス観点でのテストケースの追加。

Filterを指定して実行

AllPairs の コンストラクタには、FIlter関数が指定でき、ありえない組み合わせを除外できます。

from allpairspy import AllPairs

def is_valid_combination(row):
    """
    This is a filtering function. Filtering functions should return True
    if combination is valid and False otherwise.

    Test row that is passed here can be incomplete.
    To prevent search for unnecessary items filtering function
    is executed with found subset of data to validate it.
    """
    n = len(row)
    # Listのサイズによる判定、1、2要素目の組み合わせで判断したい場合は、 if n > 1 とかで判定してもOK
    # 要素数が膨大な場合は、if n > 1 にした方がパフォーマンスが出る。   
    if n > 4:
        # Brand Y does not support Windows 98
        if "98" == row[1] and "Brand Y" == row[0]:
            return False

        # Brand X does not work with XP
        if "XP" == row[1] and "Brand X" == row[0]:
            return False

        # Contractors are billed in 30 min increments
        if "Contr." == row[3] and row[4] < 30:
            return False

    return True

parameters = [
    ["Brand X", "Brand Y"],
    ["98", "NT", "2000", "XP"],
    ["Internal", "Modem"],
    ["Salaried", "Hourly", "Part-Time", "Contr."],
    [6, 10, 15, 30, 60]
]

print("PAIRWISE:")
for i, pairs in enumerate(AllPairs(parameters, filter_func=is_valid_combination)):
    print("{:2d}: {}".format(i + 1, pairs))

PAIRWISE:
 1: ['Brand X', '98', 'Internal', 'Salaried', 6]
 2: ['Brand Y', 'NT', 'Modem', 'Hourly', 6]
 3: ['Brand Y', '2000', 'Internal', 'Part-Time', 10]
 4: ['Brand X', '2000', 'Modem', 'Contr.', 30]
 5: ['Brand X', 'NT', 'Internal', 'Hourly', 15]
 6: ['Brand Y', 'XP', 'Modem', 'Salaried', 15]
 7: ['Brand Y', 'XP', 'Internal', 'Contr.', 60]
 8: ['Brand X', '98', 'Modem', 'Part-Time', 60]
 9: ['Brand X', 'NT', 'Modem', 'Part-Time', 10]
10: ['Brand Y', '2000', 'Internal', 'Salaried', 30]
11: ['Brand Y', 'XP', 'Internal', 'Part-Time', 6]
12: ['Brand Y', '2000', 'Internal', 'Hourly', 60]
13: ['Brand Y', 'NT', 'Internal', 'Contr.', 60]
14: ['Brand Y', 'XP', 'Internal', 'Hourly', 10]
15: ['Brand Y', 'NT', 'Internal', 'Salaried', 60]

直積 (全組み合わせ)でFilterを実行する

itertools.productにはfilter関数は指定できないので、filterフィルタリングします。

import itertools

def is_valid_combination(row):
    # Brand Y does not support Windows 98
    if "98" == row[1] and "Brand Y" == row[0]:
        return False

    # Brand X does not work with XP
    if "XP" == row[1] and "Brand X" == row[0]:
        return False

    # Contractors are billed in 30 min increments
    if "Contr." == row[3] and row[4] < 30:
        return False

    return True

a = ["Brand X", "Brand Y"]
b = ["98", "NT", "2000", "XP"]
c = ["Internal", "Modem"]
d = ["Salaried", "Hourly", "Part-Time", "Contr."]
e = [6, 10, 15, 30, 60]

print("PRODUCT:")
elems = filter(is_valid_combination,itertools.product(a, b,c,d,e))
for i, pairs in enumerate(elems):
    print("{:2d}: {}".format(i + 1, pairs))

PRODUCT:
 1: ('Brand X', '98', 'Internal', 'Salaried', 6)
 2: ('Brand X', '98', 'Internal', 'Salaried', 10)
 3: ('Brand X', '98', 'Internal', 'Salaried', 15)
 4: ('Brand X', '98', 'Internal', 'Salaried', 30)
 5: ('Brand X', '98', 'Internal', 'Salaried', 60)
 6: ('Brand X', '98', 'Internal', 'Hourly', 6)
 7: ('Brand X', '98', 'Internal', 'Hourly', 10)
 8: ('Brand X', '98', 'Internal', 'Hourly', 15)
 9: ('Brand X', '98', 'Internal', 'Hourly', 30)
10: ('Brand X', '98', 'Internal', 'Hourly', 60)
11: ('Brand X', '98', 'Internal', 'Part-Time', 6)
12: ('Brand X', '98', 'Internal', 'Part-Time', 10)
13: ('Brand X', '98', 'Internal', 'Part-Time', 15)
14: ('Brand X', '98', 'Internal', 'Part-Time', 30)
15: ('Brand X', '98', 'Internal', 'Part-Time', 60)
16: ('Brand X', '98', 'Internal', 'Contr.', 30)
17: ('Brand X', '98', 'Internal', 'Contr.', 60)
18: ('Brand X', '98', 'Modem', 'Salaried', 6)
19: ('Brand X', '98', 'Modem', 'Salaried', 10)
20: ('Brand X', '98', 'Modem', 'Salaried', 15)
21: ('Brand X', '98', 'Modem', 'Salaried', 30)
22: ('Brand X', '98', 'Modem', 'Salaried', 60)
23: ('Brand X', '98', 'Modem', 'Hourly', 6)
24: ('Brand X', '98', 'Modem', 'Hourly', 10)
25: ('Brand X', '98', 'Modem', 'Hourly', 15)
26: ('Brand X', '98', 'Modem', 'Hourly', 30)
27: ('Brand X', '98', 'Modem', 'Hourly', 60)
28: ('Brand X', '98', 'Modem', 'Part-Time', 6)
29: ('Brand X', '98', 'Modem', 'Part-Time', 10)
30: ('Brand X', '98', 'Modem', 'Part-Time', 15)
31: ('Brand X', '98', 'Modem', 'Part-Time', 30)
32: ('Brand X', '98', 'Modem', 'Part-Time', 60)
33: ('Brand X', '98', 'Modem', 'Contr.', 30)
34: ('Brand X', '98', 'Modem', 'Contr.', 60)
35: ('Brand X', 'NT', 'Internal', 'Salaried', 6)
36: ('Brand X', 'NT', 'Internal', 'Salaried', 10)
37: ('Brand X', 'NT', 'Internal', 'Salaried', 15)
38: ('Brand X', 'NT', 'Internal', 'Salaried', 30)
39: ('Brand X', 'NT', 'Internal', 'Salaried', 60)
40: ('Brand X', 'NT', 'Internal', 'Hourly', 6)
41: ('Brand X', 'NT', 'Internal', 'Hourly', 10)
42: ('Brand X', 'NT', 'Internal', 'Hourly', 15)
43: ('Brand X', 'NT', 'Internal', 'Hourly', 30)
44: ('Brand X', 'NT', 'Internal', 'Hourly', 60)
45: ('Brand X', 'NT', 'Internal', 'Part-Time', 6)
46: ('Brand X', 'NT', 'Internal', 'Part-Time', 10)
47: ('Brand X', 'NT', 'Internal', 'Part-Time', 15)
48: ('Brand X', 'NT', 'Internal', 'Part-Time', 30)
49: ('Brand X', 'NT', 'Internal', 'Part-Time', 60)
50: ('Brand X', 'NT', 'Internal', 'Contr.', 30)
51: ('Brand X', 'NT', 'Internal', 'Contr.', 60)
52: ('Brand X', 'NT', 'Modem', 'Salaried', 6)
53: ('Brand X', 'NT', 'Modem', 'Salaried', 10)
54: ('Brand X', 'NT', 'Modem', 'Salaried', 15)
55: ('Brand X', 'NT', 'Modem', 'Salaried', 30)
56: ('Brand X', 'NT', 'Modem', 'Salaried', 60)
57: ('Brand X', 'NT', 'Modem', 'Hourly', 6)
58: ('Brand X', 'NT', 'Modem', 'Hourly', 10)
59: ('Brand X', 'NT', 'Modem', 'Hourly', 15)
60: ('Brand X', 'NT', 'Modem', 'Hourly', 30)
61: ('Brand X', 'NT', 'Modem', 'Hourly', 60)
62: ('Brand X', 'NT', 'Modem', 'Part-Time', 6)
63: ('Brand X', 'NT', 'Modem', 'Part-Time', 10)
64: ('Brand X', 'NT', 'Modem', 'Part-Time', 15)
65: ('Brand X', 'NT', 'Modem', 'Part-Time', 30)
66: ('Brand X', 'NT', 'Modem', 'Part-Time', 60)
67: ('Brand X', 'NT', 'Modem', 'Contr.', 30)
68: ('Brand X', 'NT', 'Modem', 'Contr.', 60)
69: ('Brand X', '2000', 'Internal', 'Salaried', 6)
70: ('Brand X', '2000', 'Internal', 'Salaried', 10)
71: ('Brand X', '2000', 'Internal', 'Salaried', 15)
72: ('Brand X', '2000', 'Internal', 'Salaried', 30)
73: ('Brand X', '2000', 'Internal', 'Salaried', 60)
74: ('Brand X', '2000', 'Internal', 'Hourly', 6)
75: ('Brand X', '2000', 'Internal', 'Hourly', 10)
76: ('Brand X', '2000', 'Internal', 'Hourly', 15)
77: ('Brand X', '2000', 'Internal', 'Hourly', 30)
78: ('Brand X', '2000', 'Internal', 'Hourly', 60)
79: ('Brand X', '2000', 'Internal', 'Part-Time', 6)
80: ('Brand X', '2000', 'Internal', 'Part-Time', 10)
81: ('Brand X', '2000', 'Internal', 'Part-Time', 15)
82: ('Brand X', '2000', 'Internal', 'Part-Time', 30)
83: ('Brand X', '2000', 'Internal', 'Part-Time', 60)
84: ('Brand X', '2000', 'Internal', 'Contr.', 30)
85: ('Brand X', '2000', 'Internal', 'Contr.', 60)
86: ('Brand X', '2000', 'Modem', 'Salaried', 6)
87: ('Brand X', '2000', 'Modem', 'Salaried', 10)
88: ('Brand X', '2000', 'Modem', 'Salaried', 15)
89: ('Brand X', '2000', 'Modem', 'Salaried', 30)
90: ('Brand X', '2000', 'Modem', 'Salaried', 60)
91: ('Brand X', '2000', 'Modem', 'Hourly', 6)
92: ('Brand X', '2000', 'Modem', 'Hourly', 10)
93: ('Brand X', '2000', 'Modem', 'Hourly', 15)
94: ('Brand X', '2000', 'Modem', 'Hourly', 30)
95: ('Brand X', '2000', 'Modem', 'Hourly', 60)
96: ('Brand X', '2000', 'Modem', 'Part-Time', 6)
97: ('Brand X', '2000', 'Modem', 'Part-Time', 10)
98: ('Brand X', '2000', 'Modem', 'Part-Time', 15)
99: ('Brand X', '2000', 'Modem', 'Part-Time', 30)
100: ('Brand X', '2000', 'Modem', 'Part-Time', 60)
101: ('Brand X', '2000', 'Modem', 'Contr.', 30)
102: ('Brand X', '2000', 'Modem', 'Contr.', 60)
103: ('Brand Y', 'NT', 'Internal', 'Salaried', 6)
104: ('Brand Y', 'NT', 'Internal', 'Salaried', 10)
105: ('Brand Y', 'NT', 'Internal', 'Salaried', 15)
106: ('Brand Y', 'NT', 'Internal', 'Salaried', 30)
107: ('Brand Y', 'NT', 'Internal', 'Salaried', 60)
108: ('Brand Y', 'NT', 'Internal', 'Hourly', 6)
109: ('Brand Y', 'NT', 'Internal', 'Hourly', 10)
110: ('Brand Y', 'NT', 'Internal', 'Hourly', 15)
111: ('Brand Y', 'NT', 'Internal', 'Hourly', 30)
112: ('Brand Y', 'NT', 'Internal', 'Hourly', 60)
113: ('Brand Y', 'NT', 'Internal', 'Part-Time', 6)
114: ('Brand Y', 'NT', 'Internal', 'Part-Time', 10)
115: ('Brand Y', 'NT', 'Internal', 'Part-Time', 15)
116: ('Brand Y', 'NT', 'Internal', 'Part-Time', 30)
117: ('Brand Y', 'NT', 'Internal', 'Part-Time', 60)
118: ('Brand Y', 'NT', 'Internal', 'Contr.', 30)
119: ('Brand Y', 'NT', 'Internal', 'Contr.', 60)
120: ('Brand Y', 'NT', 'Modem', 'Salaried', 6)
121: ('Brand Y', 'NT', 'Modem', 'Salaried', 10)
122: ('Brand Y', 'NT', 'Modem', 'Salaried', 15)
123: ('Brand Y', 'NT', 'Modem', 'Salaried', 30)
124: ('Brand Y', 'NT', 'Modem', 'Salaried', 60)
125: ('Brand Y', 'NT', 'Modem', 'Hourly', 6)
126: ('Brand Y', 'NT', 'Modem', 'Hourly', 10)
127: ('Brand Y', 'NT', 'Modem', 'Hourly', 15)
128: ('Brand Y', 'NT', 'Modem', 'Hourly', 30)
129: ('Brand Y', 'NT', 'Modem', 'Hourly', 60)
130: ('Brand Y', 'NT', 'Modem', 'Part-Time', 6)
131: ('Brand Y', 'NT', 'Modem', 'Part-Time', 10)
132: ('Brand Y', 'NT', 'Modem', 'Part-Time', 15)
133: ('Brand Y', 'NT', 'Modem', 'Part-Time', 30)
134: ('Brand Y', 'NT', 'Modem', 'Part-Time', 60)
135: ('Brand Y', 'NT', 'Modem', 'Contr.', 30)
136: ('Brand Y', 'NT', 'Modem', 'Contr.', 60)
137: ('Brand Y', '2000', 'Internal', 'Salaried', 6)
138: ('Brand Y', '2000', 'Internal', 'Salaried', 10)
139: ('Brand Y', '2000', 'Internal', 'Salaried', 15)
140: ('Brand Y', '2000', 'Internal', 'Salaried', 30)
141: ('Brand Y', '2000', 'Internal', 'Salaried', 60)
142: ('Brand Y', '2000', 'Internal', 'Hourly', 6)
143: ('Brand Y', '2000', 'Internal', 'Hourly', 10)
144: ('Brand Y', '2000', 'Internal', 'Hourly', 15)
145: ('Brand Y', '2000', 'Internal', 'Hourly', 30)
146: ('Brand Y', '2000', 'Internal', 'Hourly', 60)
147: ('Brand Y', '2000', 'Internal', 'Part-Time', 6)
148: ('Brand Y', '2000', 'Internal', 'Part-Time', 10)
149: ('Brand Y', '2000', 'Internal', 'Part-Time', 15)
150: ('Brand Y', '2000', 'Internal', 'Part-Time', 30)
151: ('Brand Y', '2000', 'Internal', 'Part-Time', 60)
152: ('Brand Y', '2000', 'Internal', 'Contr.', 30)
153: ('Brand Y', '2000', 'Internal', 'Contr.', 60)
154: ('Brand Y', '2000', 'Modem', 'Salaried', 6)
155: ('Brand Y', '2000', 'Modem', 'Salaried', 10)
156: ('Brand Y', '2000', 'Modem', 'Salaried', 15)
157: ('Brand Y', '2000', 'Modem', 'Salaried', 30)
158: ('Brand Y', '2000', 'Modem', 'Salaried', 60)
159: ('Brand Y', '2000', 'Modem', 'Hourly', 6)
160: ('Brand Y', '2000', 'Modem', 'Hourly', 10)
161: ('Brand Y', '2000', 'Modem', 'Hourly', 15)
162: ('Brand Y', '2000', 'Modem', 'Hourly', 30)
163: ('Brand Y', '2000', 'Modem', 'Hourly', 60)
164: ('Brand Y', '2000', 'Modem', 'Part-Time', 6)
165: ('Brand Y', '2000', 'Modem', 'Part-Time', 10)
166: ('Brand Y', '2000', 'Modem', 'Part-Time', 15)
167: ('Brand Y', '2000', 'Modem', 'Part-Time', 30)
168: ('Brand Y', '2000', 'Modem', 'Part-Time', 60)
169: ('Brand Y', '2000', 'Modem', 'Contr.', 30)
170: ('Brand Y', '2000', 'Modem', 'Contr.', 60)
171: ('Brand Y', 'XP', 'Internal', 'Salaried', 6)
172: ('Brand Y', 'XP', 'Internal', 'Salaried', 10)
173: ('Brand Y', 'XP', 'Internal', 'Salaried', 15)
174: ('Brand Y', 'XP', 'Internal', 'Salaried', 30)
175: ('Brand Y', 'XP', 'Internal', 'Salaried', 60)
176: ('Brand Y', 'XP', 'Internal', 'Hourly', 6)
177: ('Brand Y', 'XP', 'Internal', 'Hourly', 10)
178: ('Brand Y', 'XP', 'Internal', 'Hourly', 15)
179: ('Brand Y', 'XP', 'Internal', 'Hourly', 30)
180: ('Brand Y', 'XP', 'Internal', 'Hourly', 60)
181: ('Brand Y', 'XP', 'Internal', 'Part-Time', 6)
182: ('Brand Y', 'XP', 'Internal', 'Part-Time', 10)
183: ('Brand Y', 'XP', 'Internal', 'Part-Time', 15)
184: ('Brand Y', 'XP', 'Internal', 'Part-Time', 30)
185: ('Brand Y', 'XP', 'Internal', 'Part-Time', 60)
186: ('Brand Y', 'XP', 'Internal', 'Contr.', 30)
187: ('Brand Y', 'XP', 'Internal', 'Contr.', 60)
188: ('Brand Y', 'XP', 'Modem', 'Salaried', 6)
189: ('Brand Y', 'XP', 'Modem', 'Salaried', 10)
190: ('Brand Y', 'XP', 'Modem', 'Salaried', 15)
191: ('Brand Y', 'XP', 'Modem', 'Salaried', 30)
192: ('Brand Y', 'XP', 'Modem', 'Salaried', 60)
193: ('Brand Y', 'XP', 'Modem', 'Hourly', 6)
194: ('Brand Y', 'XP', 'Modem', 'Hourly', 10)
195: ('Brand Y', 'XP', 'Modem', 'Hourly', 15)
196: ('Brand Y', 'XP', 'Modem', 'Hourly', 30)
197: ('Brand Y', 'XP', 'Modem', 'Hourly', 60)
198: ('Brand Y', 'XP', 'Modem', 'Part-Time', 6)
199: ('Brand Y', 'XP', 'Modem', 'Part-Time', 10)
200: ('Brand Y', 'XP', 'Modem', 'Part-Time', 15)
201: ('Brand Y', 'XP', 'Modem', 'Part-Time', 30)
202: ('Brand Y', 'XP', 'Modem', 'Part-Time', 60)
203: ('Brand Y', 'XP', 'Modem', 'Contr.', 30)
204: ('Brand Y', 'XP', 'Modem', 'Contr.', 60)

allpairspyでも、filter でも同様のfilter関数が指定できます。


Webシステムにおける組み合わせテストのルール

個人的には、Webシステムにおいては、以下のような考えで、組み合わせテストを実施しようかと思います。
独断と偏見です。

  • ミッションクリティカルではない、且つ、金額計算、生命が関わる仕組みではない場合

    • オールペア法による組み合わせ網羅を基本とし、オールペア法のテストケースはコスト範囲内であれば、最低限実施する。
    • その他の組み合わせについてはサービス担当者の過去の経験、及び勘を働かせて追加する。
  • ミッションクリティカル、又は、金額計算、生命が関わる仕組みの場合

    • オールペア法、直行表の組み合わせ網羅を基本とする。
    • サービス担当者の過去の経験、及び勘と、障害発生時のリスクを勘案してテストケースを追加する。
    • 予算によっては、泣く<wbr>泣くテストケースを削減する。

参考

以下、参考にした記事です。

以上です。

コメント