如何使用集合的组合作为测试数据

时间:2008-08-02 21:34:24

标签: unit-testing language-agnostic testing

我想测试一个带有一组边缘情况和正常值的元组的函数。例如,在测试一个函数,当给定三个形成有效三角形的长度时,返回true,我会有特定情况,负数/小数/大数,接近溢出的值等等;更重要的是,主要目的是生成这些值的组合,而不重复,以获得一组测试数据。

(inf,0,-1), (5,10,1000), (10,5,5), (0,-1,5), (1000,inf,inf),
...
  

作为一个注释:我实际上知道答案,但它可能对其他人有帮助,对这里的人来说是一个挑战! - 稍后会发布我的回答。

5 个答案:

答案 0 :(得分:15)

当然,特别是在处理大量这些排列/组合时,我绝对可以看到第一遍是一个问题。

在python中有趣的实现,虽然我在C和Ocaml中写了一个很好的基于“算法515”(见下文)。他在Fortran中写了他的所有“算法XX”论文,那就是组装或c。我不得不重新编写它并进行一些小改进以使用不是数字范围的数组。这个随机访问,我仍在努力获得Knuth第4卷第2卷中提到的一些很好的实现。我将向读者解释这是如何工作的。虽然如果有人好奇,我也不反对写点什么。

/** [combination c n p x]
 * get the [x]th lexicographically ordered set of [p] elements in [n]
 * output is in [c], and should be sizeof(int)*[p] */
void combination(int* c,int n,int p, int x){
    int i,r,k = 0;
    for(i=0;i<p-1;i++){
        c[i] = (i != 0) ? c[i-1] : 0;
        do {
            c[i]++;
            r = choose(n-c[i],p-(i+1));
            k = k + r;
        } while(k < x);
        k = k - r;
    }
    c[p-1] = c[p-2] + x - k;
}

〜“算法515:从词典索引生成矢量”; Buckles,B.P。和Lybanon,M。ACM Transactions on Mathematical Software,Vol。 1977年6月3日第2期。

答案 1 :(得分:4)

使用全新的Python 2.6,您可以使用itertools模块获得标准解决方案,该模块返回可迭代的笛卡尔积:

import itertools

print list(itertools.product([1,2,3], [4,5,6]))
   [(1, 4), (1, 5), (1, 6),
   (2, 4), (2, 5), (2, 6),
   (3, 4), (3, 5), (3, 6)]

您可以提供一个“重复”参数来执行带有iterable及其自身的产品:

print list(itertools.product([1,2], repeat=3))
[(1, 1, 1), (1, 1, 2), (1, 2, 1), (1, 2, 2),
(2, 1, 1), (2, 1, 2), (2, 2, 1), (2, 2, 2)]

你也可以用组合调整一些东西:

print list(itertools.combinations('123', 2))
[('1', '2'), ('1', '3'), ('2', '3')]

如果订单很重要,那就是排列:

print list(itertools.permutations([1,2,3,4], 2))
[(1, 2), (1, 3), (1, 4),
   (2, 1), (2, 3), (2, 4),
   (3, 1), (3, 2), (3, 4),
   (4, 1), (4, 2), (4, 3)]

当然,所有那些很酷的东西并不完全相同,但你可以用某种方式来解决你的问题。

请记住,您可以使用list(),tuple()和set()将元组或列表转换为集合,反之亦然。

答案 2 :(得分:3)

有趣的问题!

我会通过选择组合来实现这一点,如python中的以下内容。最困难的部分可能是首次通过验证,即if f(1,2,3) returns true,这是正确的结果吗?一旦验证了,那么这是回归测试的良好基础。

可能最好制作一组你知道的测试用例都是正确的(例如3,4,5这个三角形例),并且你知道的一组测试用例都是假的(例如0,1,INF)。然后,您可以更轻松地验证测试是否正确。

# xpermutations from http://code.activestate.com/recipes/190465
from xpermutations import *

lengths=[-1,0,1,5,10,0,1000,'inf']
for c in xselections(lengths,3):        # or xuniqueselections
    print c
(-1,-1,-1);
(-1,-1,0);
(-1,-1,1);
(-1,-1,5);
(-1,-1,10);
(-1,-1,0);
(-1,-1,1000);
(-1,-1,inf);
(-1,0,-1);
(-1,0,0);
...

答案 3 :(得分:2)

我认为您可以使用Row Test Attribute(在MbUnit和更高版本的NUnit中提供)执行此操作,您可以在其中指定多个集合来填充一个单元测试。

答案 4 :(得分:0)

虽然可以创建大量测试数据并查看会发生什么,但尝试最小化所使用的数据会更有效。

从典型的质量保证角度来看,您需要识别不同的输入分类。为每个分类生成一组输入值并确定适当的输出。

以下是输入值类的示例

  • 小数字的有效三角形,如(10亿,2,十亿,20亿)
  • 具有大数字的有效三角形,例如(0.000001,0.00002,0.00003)
  • “几乎”平的有效钝角三角形,如(10,10,19.9999)
  • 有效的“几乎”平坦的锐角三角形,如(10,10,0000001)
  • 至少有一个负值的无效三角形
  • 无效三角形,其中两边的总和等于第三个
  • 无效三角形,其中两边的总和大于第三个
  • 输入非数字值

...

如果对此函数的输入分类列表感到满意,则可以创建实际的测试数据。可能,测试每个项目的所有排列将是有帮助的。 (例如(2,3,4),(2,4,3),(3,2,4),(3,4,2),(4,2,3),(4,3,2))通常,您会发现您遗漏了一些分类(例如inf作为输入参数的概念)。

一段时间内的随机数据也可能有用,可以在代码中找到奇怪的错误,但通常效率不高。

更有可能的是,此函数正在应用其他规则的某些特定上下文中使用。(例如,只有整数值或值必须以0.01为增量等)。这些将添加到输入参数的分类列表中。