测试运行

使用 QICT 进行成对测试

James McCaffrey

下载代码示例

pairwise 测试原则的实心知识是所有软件测试人员、 开发人员和经理的基本要求。在这个月已经列我解释究竟什么 pairwise 测试是,您提供一个生产质量 pairwise 测试工具名为 QICT 完整 C# 源代码。简而言之,pairwise 测试是一种技术,使您可以减少大型、 难以管理的一小得多的组,很可能揭示下测试系统中的 bug 的测试用例输入集。最好的方式解释 pairwise 测试,并向您展示我向此文章中是由两个屏幕快照的方式。请考虑在哑元 Windows 窗体基于的应用程序中 的 图 1 所示。该应用程序有四个输入的参数。第一个参数是可以接受 “ ” 或 “ b ” 的文本框控件。第二个参数是一组可采用 “ c ”、 “ d ”、 “ e ” 或 “ f ” 的值的单选按钮控件。第三个参数是可以采用 “ g ” 的值的组合框控件 “ h ” 或 “ i ”。第四个参数是一个采用值为 “ j ” 或 “ k ” 的复选框控件。这样将是一个测试用例输入的集 {“ a ”、 “ c ”、 “ g ”、 “ j ”}。虚拟应用程序共 2 * 4 * 3 * 2 = 48 可能输入集,它是肯定易于管理。但是,假设一个卡播放应用程序的每个参数可以将位置 52 值之一 (可以从普通的卡片组的游戏卡片与替换表示卡片) 的五个参数与某种排序。在这种情况下会有 52 * 52 * 52 * 52 * 52 = 380,204,032 可能输入集,这很可能是难以管理,除非您可以为每个测试集的输入,以编程方式生成预期值。

图 1 的 具有四输入参数的 A 虚应用程序

pairwise 测试的目的是生成的捕获对从每个参数的参数值的所有可能的测试集的列表。对于将在 的 图 1 所示的示例有 44 这样输入对的总计:

(a,c), (a,d), (a,e), (a,f), (a,g), (a,h), (a,i), (a,j), (a,k), (b,c), (b,d), (b,e), (b,f), (b,g), (b,h), (b,i), (b,j), (b,k), (c,g), (c,h), (c,i), (c,j), (c,k), (d,g), (d,h), (d,i), (d,j), (d,k), (e,g), (e,h), (e,i), (e,j), (e,k), (f,g), (f,h), (f,i), (f,j), (f,k), (g,j), (g,k), (h,j), (h,k), (i,j), (i,k)

现在测试集 {“ a ”、 “ c ”、 “ g ”、 “ j ”} 捕获六个 44 对:(a 的 c) (a 的 g) (一个的 j) (c,g) (c,j) 和 (g、 j)。因此成对测试设置生成的目标是以产生捕获所有 44 对的测试集的集合。在 的 图 2 中采取一看屏幕快照。

图 2 成对测试集生成与 QICT 工具

屏幕快照显示了一个名为 qict.exe 生成 12 捕获所有 44 输入的对 的 图 1 所示的方案的测试集的集合的工具。如果您跟踪通过 12 的 图 2 中生成的测试集中值的每一对,看到它们执行实际上捕获所有 44 对上面列出。因此,在此情况中我们已经减少从 48 测试用例我们可能的测试用例输入到 12 测试用例。节省 aren’t 此小的示例非常重要,但根据我显示稍后,使用 pairwise 测试可以显著减少在许多情况下的测试用例输入数目。pairwise 测试的基础假设是更频繁地涉及从不同的参数的值的交互,比在代码中涉及从特定的参数内的值的代码中找到软件缺陷。也就为虚拟应用程序在 的 图 1 中,“ ” 和 “ g ” 处理输入的应用程序代码是更有可能会引入 “ ” 和 “ b ” 处理输入的代码比一个逻辑错误。这是一个概念,在事实的方式数据表所支持的一些信息检索。

使用工具 PICT

对您有可用的几个成对测试集生成工具。我最喜欢的工具,在大多数情况下是 PICT (成对独立 Combinatorial 测试) 工具。通过我的同事适用于从现有的内部 Microsoft 成对工具的代码的 Jacek Czerwonka 写入 PICT。PICT 是从包括在 msdn.microsoft.com/testing/bb980925.aspx Microsoft 测试程序中心页的多个位置免费下载可用。如果搜索 Internet,还将找到几个其他成对测试设置生成工具。但是,PICT 是从外壳程序命令行运行的单个可执行文件。PICT 非常快速、 非常强大,应满足您的 pairwise 测试需要在大多数情况下。我已命名本文 (该独立 doesn’t 存在的任何特别) QICT 中呈现给承认 PICT 工具的重要性,该工具。

这样,原因而另一个成对测试设置生成器吗?有几个原因。  首先,虽然 PICT 是神奇工具,它用本机 c + + 代码编写和源代码不可用。此处提供的 QICT 工具是,据我可以告诉第一个生产质量成对工具编写与托管的 C# 代码。代码的可用性,可以自由地修改以满足您自己的需要 QICT。渚嬪可以修改 QICT 直接从 XML 文件或 SQL 数据库中读取其输入,也可以修改 QICT 直接发出自定义的输出格式的结果。并且您可能希望进行试验工具已经逻辑说,渚嬪通过引入约束 (测试输入集不允许的),通过引入必需的测试集,或更改该工具如何生成其测试集集合。此外,QICT 源代码的可用性允许您复制和成对的地方直接将.net 应用程序或测试工具测试设置的生成代码。最后,虽然在 Internet 上可用的几个成对测试集生成工具的源代码,其中一些工具是效率很低。渚嬪考虑带有 20 参数的情况每一个都有 10 个值。在此方案中有 10 * 10 * 10 *。..* 10 (20 次) = 1020 = 100,000,000,000,000,000,000 可能的测试用例输入。这是大量的测试用例。PICT 工具可以减少这仅 217 的成对测试集和 QICT 工具可以产生 219 或 216 测试集具体 (取决于随机数生成器的种子值如稍后解释)。但是,一个广泛引用成对测试设置的生成 Perl 中写入的工具可以产生 664 集。最后,QICT 源代码可用和算法的本文已经说明,您可以 recast QICT 以其他语言,如 Perl、 Python、 Java 或 JavaScript 濡傛灉甯屾湜。

QICT 工具

QICT 工具的代码是略过此列中的完整地展示长,但整个源代码是在 code.msdn.microsoft.com MSDN 代码库中可用。我将介绍算法和数据结构使用,连同的键代码段这样有足够的信息,可以使用并根据需要修改 QICT。QICT 的工作原理的实质是生成一个测试集一次放置每个参数值,直到在捕获对所有可能使用贪婪的算法。的 图 3 中所列 QICT 的高级算法。

图 3 的 QICT 算法

read input file
create internal data structures

create an empty testset collection
while (number of unused pairs > 0)
  for i := 1 to candidate poolSize
    create an empty candidate testset
    pick the "best" unused pair
    place best pair values into testset
    foreach remaining parameter position
      pick a "best" parameter value
      place the best value into testset
    end foreach
  end for
  determine "best" candidate testset
  add best testset to testset collection
  update unused pairs list
end while

display testset collection

若要实现此高级算法密钥确定要使用的数据结构和各种 “ 最佳 ” 选项的是何种。 QICT 源代码开始像下面这样:

static void Main(string[] args)
{
  string file = args[0];
  Random r = new Random(2);
  int numberParameters = 0;
  int numberParameterValues = 0;
  int numberPairs = 0;
  int poolSize = 20;

我编码 QICT 使用传统的过程样式,而不是采用一个面向对象的方法,以便您可以更轻松地重构 QICT,如 Perl 和 JavaScript 的有限 OOP 支持的语言。 我首先从命令行读取输入的文件。 您可以看到要使我的代码保持干净和简单,我已离开出普通错误检查要包括。 QICT 的输入的文件是使用 PICT,简单的文本文件,如下所示的相同:

Param0 中:a,b
参数:c、 d、 e、 f
等等

参数名称跟一个冒号字符并以逗号分隔的参数的合法值的列表。 参数值必须是不同的。 接下来,我实例化 Random 对象。 种子值 2 的选择是任意,但任何值将使 QICT 每次运行时生成的输入集相同的结果。 我不久解释伪随机编号的对象的目的。 我声明将被分配值时读取输入的文件的三个 int 变量。 对于将在 的 图 2 所示的示例 numberParameters 是 4、 numberParameterValues 是 11 和 numberPairs 是 44。 poolSize 变量存储为每个测试集生成的候选测试集数目。 如果您有点试验 QICT,请参阅该工具在通过调整 poolSize 的值,而是令人惊讶的是次要的方式受到影响。 QICT 的核心是主数据结构的声明。 前四个对象有:

 

int[][] legalValues = null;
string[] parameterValues = null;
int[,] allPairsDisplay = null;
List<int[]> unusedPairs = null;

legalValues 对象是交错的数组,其中每个单元格又包含 int 值的数组。 legalValues 数组持有的输入文件在内存中表示形式,以便合法值的单元格 0 持有反过来持有值 0 的数组 (表示参数值 “ 一个 ”) 和 1 (表示 “ b ”)。 事实证明直接使用字符串值是而是效率低下和表示为整数的参数值将产生明显更快的性能。 parameterValues 的字符串数组包含实际的参数值,用于 QICT 的末尾显示为字符串,而不是整数的结果。 因此,前面的示例为单元格 0 持有 “ ”、 单元格 1 持有 “ b ” 依此类推,直到单元格 10,它保存 “ k ”。 allPairsDisplay 对象是整数的二维数组。 它是对所有可能由填充的。 对于我们的示例单元格 [0,0] 包含 0 (表示 “ 一个 ”) 和单元格 (对于 “ c ”) [0,1] 保留 2 — 第一可能对。 单元格 [1,0] 包含 0 和单元格 [1,1] 保留来表示第二个对 3 (一个,d)。 unusedPairs 对象是 int 数组的泛型列表。 在 unusedPairs 中的第一个项目最初是 {0,2}。 因为每次新的测试集添加到测试设置集合 unusedPairs,而不是一个数组,使用列表集合、 綍鍒犻櫎由新的测试从 unusedPairs 设置生成对。 此外,这意味着我有 unusedPairs.Count 到达 0 时将发生一个方便的停止条件。

接下来的四个主要的程序数据结构是:

int[,] unusedPairsSearch = null;
int[] parameterPositions = null;
int[] unusedCounts = null;
List<int[]> testSets = null;

最 pairwise 测试包括 QICT 的集生成工具、 执行搜索的巨大数量。 有效的查找方法的合理性能至关重要。 这里我声明一个名为 unusedPairsSearch 的二维数组。 它是与通过 numberParameterValues,大小 numberParameterValues 方形数组其中每个单元格如果未使用相应的对一个 1 和 0 如果保存相应的对已使用或不是有效对。 最初,unusedPairsSearch 例如图 2 中的前三行是:

0 0 1 1 1 1 1 1 1 1 1
0 0 1 1 1 1 1 1 1 1 1
0 0 0 0 0 0 1 1 1 1 1

等等。

因此第一行表示对 (0,0) 和 (0,1) — 也就是一个一) 和 (a,b) — 是无效时对 (0,2) (0,3)。 . . (0,10) — — 即 (a 的 c) (一个,d) 通过 (一个,k) — 具有不尚未被捕获的测试集。 parameterPositions 数组包含指定的参数值的测试集中位置。 初始化后此数组包含值:

0 0 1 1 1 1 2 2 2 3 3

parameterPositions 的索引表示参数值和相应单元格的值表示它在测试集的位置。 这样从左面第四个单元格有索引 = 3 和值 = 1,这意味着参数值为 3 (“ d ”) 所属在位置 1 (第二个槽) 中测试集。 unusedCounts 对象是一个持有 unusedPairs 数组中的一个特定的参数值出现的次数的一维数组。 最初 unusedCounts 持有:

9 9 7 7 7 7 8 8 8 9 9

索引表示参数值和相应单元格的值是未使用的计数。 因此,从左面第四个单元格有索引 = 3 和值 = 7,最初这意味着参数值为 3 (“ d ”) 7 未使用成对出现 — (一个的 d) (b,d) (d,g) (d,h) (d,i),(d,j) 和 (d,k)。 testSets 对象持有成对的测试集结果。 最初为空,但每次生成新的测试集的增长。 每个测试集由 int 数组表示。 因此,图 2 中第一个测试在结果集是 {“ a ”、 “ c ”、 “ g ”、 “ j ”},它具有值 {0,2,6,9} 数组形式保存在 testSets 列表中。

与就地这些关键数据,结构 QICT 读取输入的文件来确定 numberParameters 和 numberParameterValues,的值,并填充 legalValues 和 parameterValues 数组。 使用相对粗鲁的方法的执行的初始读取该文件的然后重新设置文件指针并通过文件执行第二个传递。 一旦将填充 legalValues,可以扫描通过它来确定输入的对的数目:

for (int i = 0; i <= legalValues.Length - 2; ++i) {
  for (int j = i + 1; j <= legalValues.Length - 1; ++j) {
    numberPairs += (legalValues[i].Length * legalValues[j].Length);
  }
}
Console.WriteLine("\nThere are " + numberPairs + " pairs ");

初始化后, legalValues 中的第一行包含 {0,1} 和第二行包含 {2,3,4,5}。 请注意,在对由这些两行是 (0,2) (0,3) (0,4) (0,5) (1,2) (1,3) (1,4) 和 (1,5) 和一般情况下对由 legalValues 中任何两个行的数目是它等于行的行的 Length 属性的两行中的值的数量的乘积。 在 QICT 代码的下一部分将填充 unusedPairs 列表:

unusedPairs = new List<int[]>();
for (int i = 0; i <= legalValues.Length - 2; ++i) {
  for (int j = i + 1; j <= legalValues.Length - 1; ++j) {
    int[] firstRow = legalValues[i];
    int[] secondRow = legalValues[j];
    for (int x = 0; x < firstRow.Length; ++x) {
      for (int y = 0; y < secondRow.Length; ++y) {
        int[] aPair = new int[2];
        aPair[0] = firstRow[x];
        aPair[1] = secondRow[y];
        unusedPairs.Add(aPair);
      }
    }
  }
}

我在这里抓取 legalValues 中的行的每一对 i 和 j 使用索引。 接下来,我将遍历中每个行对使用索引值 x 和 y。 广泛使用嵌套像下面这样的循环是代码的多的一个 hallmark combinatorial。 写入此类代码时我始终通过绘制手上一张纸因为 ’s 相当容易犯错不在关系图的情况下涉及到的数组。 后填充 unusedPairs 列表,使用相同的嵌套的循环结构来填充 allPairsDisplay 和 unusedPairsSearch 数组。 初始化代码接下来通过循环访问 legalValues 填充 parameterPositions 数组:

parameterPositions = new int[numberParameterValues];
int k = 0;
for (int i = 0; i < legalValues.Length; ++i) {
  int[] curr = legalValues[i];
  for (int j = 0; j < curr.Length; ++j) {
    parameterPositions[k++] = i;
  }
}

初始化代码可以确定通过填充 unusedCounts 数组:

unusedCounts = new int[numberParameterValues];
for (int i = 0; i < allPairsDisplay.GetLength(0); ++i) {
  ++unusedCounts[allPairsDisplay[i, 0]];
  ++unusedCounts[allPairsDisplay[i, 1]];
}

此处,作为在很多 QICT 例程我利用这一事实 C# 自动初始化为 0 的 int 数组中的所有单元格。 如果希望为面向对象的样式 recast QICT 所有这些初始化例程将很可能最适合放置在对象构造函数中或在一个显式 Initialize() 方法可能是。 主处理循环开始:

testSets = new List<int[]>();
while (unusedPairs.Count > 0) {
  int[][] candidateSets = new int[poolSize][];
  for (int candidate = 0; candidate < poolSize; ++candidate) {
    int[] testSet = new int[numberParameters];
  // fill candidate testSets
  }
  // copy best testSet into testSets collection; upate data structues
}

因为已知的候选测试集数目是 poolSize,
I 可以实例化一个数组,而不是使用动态调整大小的 List 对象。 请注意 unusedPairs 集合的大小控制主处理循环退出。 现在它 ’s 挑选 “ 最佳 ” 的未使用的对时间 — 和事情现在开始变得真正感兴趣:

int bestWeight = 0;
int indexOfBestPair = 0;
for (int i = 0; i < unusedPairs.Count; ++i) {
  int[] curr = unusedPairs[i];
  int weight = unusedCounts[curr[0]] + unusedCounts[curr[1]];
  if (weight > bestWeight) {
    bestWeight = weight;
    indexOfBestPair = i;
  }
}

这里我定义最佳意味着未使用的对具有最高的未使用的单个参数值的总和。 渚嬪如果 “ 一个 ” 出现一次在当前列表中的未使用对,“ b ” 出现两次 “ c ” 三次和 “ d ” 四次然后对 (a,c) 有权重 1 + 3 = 4,对 (b、 d) 有权重 (b、 d) 2 + 4 = 6,以便对 (b、 d) 将选择 (a,c) 上。

有许多您可能想要浏览其他权值方案。 渚嬪使用某种类型的乘法将为提供更高的权重对具有极值的未使用的计数与对相比具有未使用计数比较靠近在一起。 另一种可能是跟踪使用的计数 — 的参数值出现在已添加到结果 testSets 集合在测试集的次数 — 并选取如最佳配对一个具有最少使用的计数。 一旦在确定最适合的未使用的对我创建两个单元格数组以保存对值,并确定的位置集中测试所属的每个值:

int[] best = new int[2];
unusedPairs[indexOfBestPair].CopyTo(best, 0);
int firstPos = parameterPositions[best[0]];
int secondPos = parameterPositions[best[1]];

此时有一个空的测试集和一对值放置在测试集中以及我知道值所属的位置在测试集中位置。 下一步是生成的测试集中剩余的位置参数值。 现在,而不是填充某些固定顺序 (从高到低索引) 中的测试集位置,证明它是以填充按随机顺序设置测试可能更好。 首先,I 生成持有参数位置按顺序的数组:

int[] ordering = new int[numberParameters];
for (int i = 0; i < numberParameters; ++i) 
  ordering[i] = i;

接下来,我重新排列通过在从最佳的对前两个值的已知的位置中前两个单元格排序数组中的放置顺序:

ordering[0] = firstPos;
ordering[firstPos] = 0;
int t = ordering[1];
ordering[1] = secondPos;
ordering[secondPos] = t;

无序现在我播放剩余的位置 (从单元格 2 和向上),并使用 Knuth 无序播放算法。 这就是为什么 QICT 代码的开始处创建 Random 对象。 所产生的 QICT 的测试集数目是令人惊讶的是敏感的伪随机的数字生成器种子值的值,因此您可能希望试验几种子值。 对于与我前面,描述使用一个种子的 20,10 值参数情况 2 的值生成 219 的测试集和种子值为 6 生成 216 的测试集但 0 种子值产生 221 测试集。

for (int i = 2; i < ordering.Length; i++) {
  int j = r.Next(i, ordering.Length);
  int temp = ordering[j];
  ordering[j] = ordering[i];
  ordering[i] = temp;
}

shuffling 后, 我将从最好对两个值放到候选测试集:

testSet[firstPos] = best[0];
testSet[secondPos] = best[1];

现在来自 QICT 算法中最重要的部分。 我必须确定最佳的参数值,将放置在每个空测试集位置。 使用该技术是贪婪的另一种方法。 对于每个参数位置我通过计算该测试值时与其他值已经在测试组合中的多少未使用的对设置捕获测试每个可能的合法值在该位置。 然后选择捕获最未使用的对该参数值。 若要执行此代码是 QICT 的一部分,trickiest 和 的 图 4 中列出。

图 4 填充测试设置具有最佳的参数值

for (int i = 2; i < numberParameters; ++i) {
  int currPos = ordering[i];
  int[] possibleValues = legalValues[currPos];
  int currentCount = 0;
  int highestCount = 0;
  int bestJ = 0; 
  for (int j = 0; j < possibleValues.Length; ++j) {
    currentCount = 0;
    for (int p = 0; p < i; ++p) {
      int[] candidatePair = new int[] { possibleValues[j],
        testSet[ordering[p]] };
      if (unusedPairsSearch[candidatePair[0], candidatePair[1]] == 1 ||
        unusedPairsSearch[candidatePair[1], candidatePair[0]] == 1)
        ++currentCount;
    }
    if (currentCount > highestCount) {
      highestCount = currentCount;
      bestJ = j;
    }
  }
  testSet[currPos] = possibleValues[bestJ];
}

在 的 图 4 中最外层循环是测试集职位 (由 numberParameters 给定),小于两个总数的计数 (由于两个点都由最佳对使用的)。 在该循环内我提取通过查看到更早版本创建排序数组填充当前点的位置。 currentCount 变量保存捕获的测试参数值的未使用对的数目。 请注意因为我正在填充按随机顺序测试集位置,候选对值可以是顺序,因此我需要检查两种可能性,当我执行了查阅操作到 unusedPairsSearch 数组。 的 图 4 中代码的结尾将有一个候选测试具有每个位置中使用贪婪算法选择的值集。 现在只需添加到候选项集合中设置此候选测试:

candidateSets[candidate] = testSet;

此时,我有 n = poolSize 候选测试集和我需要选择最佳的这些添加到主 testSet 结果集合中。 我可以假定第一个候选测试集捕获最未使用的对,并只是循环访问每个候选起始于位置 0,但再次,引入一些随机性产生更好的结果。 我选取该候选内的随机专色,并假定它是最佳的候选:

int indexOfBestCandidate = r.Next(candidateSets.Length);
int mostPairsCaptured =
  NumberPairsCaptured(candidateSets[indexOfBestCandidate],
    unusedPairsSearch);

这里我可以使用名为 NumberPairsCaptured() 的一些 helper 函数来确定多少未使用的成对捕获的给定的测试集。 helper 函数是:

static int NumberPairsCaptured(int[] ts, int[,] unusedPairsSearch) 
{
  int ans = 0;
  for (int i = 0; i <= ts.Length - 2; ++i) {
    for (int j = i + 1; j <= ts.Length - 1; ++j) {
      if (unusedPairsSearch[ts[i], ts[j]] == 1)
        ++ans;
    }
  }
  return ans;
}

现在我遍历每个候选测试集跟踪的捕获最未使用的成对的一个位置:

for (int i = 0; i < candidateSets.Length; ++i) {
  int pairsCaptured = NumberPairsCaptured(candidateSets[i],
    unusedPairsSearch);
  if (pairsCaptured > mostPairsCaptured) {
    mostPairsCaptured = pairsCaptured;
    indexOfBestCandidate = i;
  }
}

并立即复制到主结果 testSets List 对象设置了最佳候选测试:

int[] bestTestSet = new int[numberParameters];
candidateSets[indexOfBestCandidate].CopyTo(bestTestSet, 0);
testSets.Add(bestTestSet);

在这时我已经生成并添加一个新的测试集,因此我必须更新所有数据结构所影响即,在 unusedPairs 列表 (通过删除所有对由新的测试集生成的),unusedCounts 数组 (按递减计数中新的测试集的每个参数值为),和 unusedPairsSearch 矩阵 (通过翻转与生成新的测试从 1 设置为 0 的每一对相关联的值)。

现在我 ’m 我主处理循环的结尾处。 继续生成候选、 选择最佳候选、 testSets 中添加最佳候选和更新数据结构的操作。 在处理将结束时未使用的对的数目达到 0。

然后我显示最终的结果:

Console.WriteLine("\nResult testsets: \n");
for (int i = 0; i < testSets.Count; ++i) {
  Console.Write(i.ToString().PadLeft(3) + ": ");
  int[] curr = testSets[i];
  for (int j = 0; j < numberParameters; ++j) {
    Console.Write(parameterValues[curr[j]] + " ");
  }
  Console.WriteLine("");
}
  Console.WriteLine("");
}

正如我前面提到的那样,如果您正在修改以满足自己特定的测试方案的 QICT,要发出直接向 SQL 数据库或其他窗体的存储空间的 XML 文件的结果。

产生更好的系统

pairwise 测试是一种 combinatorial 的技术与 probabilistic 的因素。 成对测试设置的生成是一个重要的技术,但 isn’t 幻。 请记住成对技术只是减少在仅有太多的测试事例处理的情况下的测试用例输入数目。 成对测试设置的生成不会创建测试用例预期的结果。 您应始终通过使用如看边界条件的普通测试原则开始,依此类推使用纯随机输入,然后使用 pairwise 测试补充测试用例生成。 此外,作为一般的规则的法则多个测试是更好的因此有 ’s 为什么 can’t 添加附加的测试用例输入成对生成工具所产生的那些没有理由。 尽管 pairwise 测试是在许多情况下非常有用的请务必在它仅在适当时使用。

我已找到是非常有用,对于配置测试的测试方法接受模块枚举值和测试 SQL 数据库的其中一个表中的每一列都有不同值的相对较小数目的成对测试设置的生成。 pairwise 测试不一定是一个好的方法,对于您可以以编程方式生成测试案例预期的结果 (并因此处理较大的测试用例输入集) 时具有的测试用例输入或相对较小的数字的方案。 和 pairwise 测试不能正常使用时输入的值向下测试系统不是离散。 但是,甚至在可能的参数值的数目是非常大的情况下您可能能够有效地使用成对的测试事例通过分隔成等价类的参数值输入生成。 使用正确、 pairwise 时测试设置的生成是一个重要的技术,它可以帮助您制作更好的软件系统。

**Dr。**James McCaffrey 伏特信息科学 Inc.他可以在其中管理软件工程师的技术培训的工作原理基于在 Microsoft 已经雷蒙德,Wash., 校园。他曾几个包括 Internet Explorer 和 MSN 搜索的 Microsoft 产品和是 的作者  .NET 测试自动化食谱:一个问题解决方案方法(Apress, 2006)可通过 jmccaffrey@volt.comv-jammc@microsoft.com 与 James 联系。

感谢到下面的技术专家为审阅此文章:Jacek Czerwonka

testrun@microsoft.com James 为发送您的问题和批注。