2011-10-06 107 views
11

我使用googletest来实现测试开始,在文档中横跨这句话无意中发现关于value-parameterized tests数据驱动测试不好吗?

  • 要测试在各种输入您的密码(又称为数据驱动 测试)。这个功能很容易被滥用,所以请在做这件事时练习一下你的好感 !

我觉得做以下,并想听听你对此事的投入和意见时,我确实是“滥用”的系统。

假设我们有以下代码:

template<typename T> 
struct SumMethod { 
    T op(T x, T y) { return x + y; } 
}; 

// optimized function to handle different input array sizes 
// in the most efficient way 
template<typename T, class Method> 
T f(T input[], int size) { 
    Method m; 
    T result = (T) 0; 
    if(size <= 128) { 
     // use m.op() to compute result etc. 
     return result; 
    } 
    if(size <= 256) { 
     // use m.op() to compute result etc. 
     return result; 
    } 
    // ... 
} 

// naive and correct, but slow alternative implementation of f() 
template<typename T, class Method> 
T f_alt(T input[], int size); 

好了,所以与此代码,它当然具有随机产生的数据,以测试的不同的输入数组大小有意义(通过用f_alt()比较)来测试f()分支机构的正确性。最重要的是,我有几个structsSumMethodMultiplyMethod等,所以我运行相当大量的试验也为不同的类型:

typedef MultiplyMethod<int> MultInt; 
typedef SumMethod<int> SumInt; 
typedef MultiplyMethod<float> MultFlt; 
// ... 
ASSERT(f<int, MultInt>(int_in, 128), f_alt<int, MultInt>(int_in, 128)); 
ASSERT(f<int, MultInt>(int_in, 256), f_alt<int, MultInt>(int_in, 256)); 
// ... 
ASSERT(f<int, SumInt>(int_in, 128), f_alt<int, SumInt>(int_in, 128)); 
ASSERT(f<int, SumInt>(int_in, 256), f_alt<int, SumInt>(int_in, 256)); 
// ... 
const float ep = 1e-6; 
ASSERT_NEAR(f<float, MultFlt>(flt_in, 128), f_alt<float, MultFlt>(flt_in, 128), ep); 
ASSERT_NEAR(f<float, MultFlt>(flt_in, 256), f_alt<float, MultFlt>(flt_in, 256), ep); 
// ... 

当然现在我的问题是:这样的任何意义,为什么这会很糟糕?

事实上,我曾与float正在竞选测试时,其中f()f_alt()将给予不同的价值观与SumMethod由于四舍五入的原因,我可以通过预分类输入数组等提高发现了一个“错误”。从这个经验我认为这实际上是一种很好的做法。

回答

10

我认为主要问题是测试“随机生成的数据”。从您的问题中不清楚,每次运行测试工具时是否重新生成这些数据。如果是,那么你的测试结果是不可重现的。如果一些测试失败了,它会在你每次运行时都失败,而不是在蓝色的月亮中运行一次,在一些奇怪的随机测试数据组合上。

所以在我看来,您应该预先生成测试数据并将其保存为测试套件的一部分。您还需要确保数据集足够大且多样化,以提供足够的代码覆盖率。此外,正如Ben Voigt在下面评论的那样,仅使用随机数据测试是不够的。您需要确定算法中的角落案例并分别进行测试,并针对这些案例量身定制数据。但是,在我看来,如果您不确定是否知道所有角落案例,那么使用随机数据进行附加测试也是有益的。你可以用随机数据偶然击中它们。

+2

由于两个原因,随机生成的数据不好 - 首先,因为如您所述,测试不可重现。其次,因为角落案件可能不会被随机生成的数据覆盖。第二个缺点是保存随机向量不会起任何作用。 –

+0

谢谢。我修改了我的答案,你当然是对的。 – haimg

+0

@haimg - 如果你在做黑箱测试,你怎么知道使用的算法和它的角落案例? :-) –

6

问题是,你不能像浮点数一样在Float上声明正确性。

检查某个epsilon内的正确性,这是计算值与期望值之间的小差异。这是你能做的最好的。对于所有浮点数都是如此。

我想我确实是这样做的时候“滥用”系统的后续

你认为你阅读本文之前,这是坏?你能说清楚它有什么不好吗?

您必须在某个时间测试此功能。你需要数据来做到这一点。虐待在哪里?

+0

当然。在上面的例子中我忘记了正确的。编辑。除此之外,我对反对写这种测试的论点更感兴趣。 – bbtrb

0

数据驱动测试很难维护,并且在较长的一段时间内,在测试本身中引入错误更容易。 详情请看:http://googletesting.blogspot.com/2008/09/tott-data-driven-traps.html

从我的观点单元测试点

而且是最有用的,当你正在做认真重构和你不知道,如果你没有在错误的方式改变的逻辑。 如果你的随机数据测试在这种改变之后会失败,那么你可以猜测:是因为数据还是因为你的改变?

然而,我认为它可能是有用的(压力测试也不是100%可重复)。但是,如果您正在使用一些持续集成系统,我不确定是否应该将包含大量随机生成数据的数据驱动测试纳入其中。 我宁愿单独部署,因为它会立刻使很多随机测试(所以每次运行时发现不好的事情的机会应该是相当高的)。但是它像正常测试套件那样占用资源太多。