11

我已经开始使用 googletest 来实现测试,并在有关值参数化测试的文档中偶然发现了这句话

  • 您想通过各种输入测试您的代码(也称为数据驱动测试)。此功能很容易被滥用,所以请在使用时锻炼您的良好意识!

我认为我在执行以下操作时确实“滥用”了系统,并希望听到您对此事的意见和意见。

假设我们有以下代码:

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()好的,因此使用此代码,使用随机生成的数据的不同输入数组大小进行测试(通过与 比较f_alt())以测试分支的正确性当然是有意义的。最重要的是,我有几个structslike SumMethod,MultiplyMethod等,所以我也在为不同类型运行相当多的测试:

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);
// ...

当然,现在我的问题是:这有什么意义吗?为什么会这样?

事实上,我在使用floats where运行测试时发现了一个“错误”,f()并且由于四舍五入f_alt()会给出不同的值,我可以通过对输入数组等进行预排序来改进它。根据这次经验,我认为这实际上是一种很好的做法。SumMethod

4

3 回答 3

11

我认为主要问题是使用“随机生成的数据”进行测试。从您的问题中不清楚是否每次运行测试工具时都会重新生成这些数据。如果是,那么您的测试结果不可重现。如果某些测试失败,那么每次运行它都会失败,而不是千载难逢,因为一些奇怪的随机测试数据组合。

因此,在我看来,您应该预先生成测试数据并将其作为测试套件的一部分。您还需要确保数据集足够大且足够多样化,以提供足够的代码覆盖率。

此外,正如 Ben Voigt 在下面评论的那样,使用随机数据进行测试是不够的。您需要识别算法中的极端情况并单独测试它们,并使用专门为这些情况量身定制的数据。但是,在我看来,当/如果您不确定自己是否了解所有极端情况时,使用随机数据进行额外测试也是有益的。您可能会使用随机数据偶然击中它们。

于 2011-10-08T18:08:21.387 回答
6

问题是您不能以与整数相同的方式断言浮点数的正确性。

检查某个 epsilon 内的正确性,这是计算值和预期值之间的微小差异。这是你能做的最好的。这适用于所有浮点数。

我认为我在执行以下操作时确实在“滥用”系统

在您阅读那篇文章之前,您是否认为这很糟糕?你能说出它的坏处吗?

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

于 2011-10-06T15:30:45.247 回答
0

它可能不好的原因之一是数据驱动的测试更难维护,并且在更长的时间内更容易在测试本身中引入错误。详情请看这里:http: //googletesting.blogspot.com/2008/09/tott-data-driven-traps.html

同样从我的角度来看,当您进行认真的重构并且您不确定是否没有以错误的方式更改逻辑时,单元测试是最有用的。如果你的随机数据测试在这种变化之后会失败,那么你可以猜测:是因为数据还是因为你的变化?

但是,我认为它可能很有用(与压力测试相同,也不是 100% 可重现)。但是,如果您使用的是一些持续集成系统,我不确定是否应该将具有大量随机生成数据的数据驱动测试包含在其中。我宁愿进行单独的部署,定期同时进行大量随机测试(因此每次运行时发现不好的东西的机会应该很高)。但是作为普通测试套件的一部分,它的资源太重了。

于 2011-10-13T23:28:40.210 回答