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

29

我希望使用一组边界情况和正常值的元组来测试一个函数。例如,当测试一个返回true的函数时,只有在给定三个长度可以组成有效三角形时才返回true,我将使用具体的情况,如负数/小数/大数,接近溢出的值等;此外,主要目的是生成这些值的组合,包括不包括重复,以便得到一组测试数据。

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

注:我其实知道这个答案,但这可能对其他人有帮助,同时也是这里的一个挑战! --我稍后会发布我的答案。


Abacus github 是一个用于 Node.JS、Python、PHP 和 Actionscript 的组合数学库(附注:我是作者)。 - Nikos M.
5个回答

18

当然,特别是处理大量这些排列/组合时,我确实可以看出第一遍将会是一个问题。

有趣的Python实现,尽管我根据“算法515”在C和Ocaml上编写了一个不错的实现(见下文)。他用Fortran写了自己的实现,因为这是“Algorithm XX”论文中常见的语言之一,当然也有汇编或C。 我不得不重新编写它并进行一些小的改进,以便与数组而不是数字范围一起使用。这个版本支持随机访问,我仍在努力实现Knuth第四卷fascicle 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. 3,No. 2,June 1977。


2
choose()函数是什么意思?它基本上返回的是 n-c[i]p-(i+1)1 吗? - Matt K
抱歉,我不理解选择行为。听起来它被定义为自反 - 选择会选择。你能用更简单的语言告诉我它是做什么的吗? - CuppM
1
“自反”不是这个术语的正确说法。它被称为“递归”,是计算机科学的基本部分。所讨论的“选择”函数是C(N,K),http://en.wikipedia.org/wiki/Binomial_coefficient。 - nlucaroni
2
需要注意的是,x是基于1而不是0的,这与人们的预期不同。 - Andrew Savinykh
即使C数组似乎将集合元素称为基于1而不是基于0,考虑到我们从一开始就增加了c [i],它永远不可能指的是第0个元素。或者我错过了什么?或者OP的意思是用-1初始化c [i]并说选择(n-c [i] -1,...)? - Subu Sankara Subramanian

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)]

您可以提供一个“repeat”参数,以使用可迭代对象和自身执行乘积:
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()将元组或列表转换为集合,反之亦然。

3

有趣的问题!

我会通过选择组合来实现,例如在Python中执行以下操作。最困难的部分可能是第一次通行验证,即如果f(1,2,3)返回true,那么这是否是一个正确的结果?一旦您已经验证了这一点,那么这是回归测试的良好基础。

可能最好制作一组您知道全为真的测试用例(例如对于这个三角形案例的3,4,5),以及一组您知道全部为假的测试用例(例如0,1,inf)。然后您可以更轻松地验证测试是否正确。

# xpermutations from http://code.activestate.com/recipes/190465
来自http://code.activestate.com/recipes/190465的xpermutations
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);
...

2
我认为您可以使用行测试属性(在MbUnit和后续版本的NUnit中可用)来实现此操作,您可以指定多个集合来填充一个单元测试。

0

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

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

以下是输入值类别的示例

  • 具有小数字的有效三角形,例如(10亿,20亿,30亿)
  • 具有大数字的有效三角形,例如(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增量为单位等) 这些都添加到了输入参数分类的列表中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接