哪一个更好?通过数据测试还是通过算法测试?

时间:2015-11-16 06:44:10

标签: scala unit-testing testing

我们正在开发Play / Scala应用程序并使用Specs2进行测试。我们的大多数测试都是针对控制器的。

我们为数据库的每个实体创建了一个数据样本生成器,并使用它们生成测试数据。这些样本生成器尝试生成各种数据场景。

对于每个测试我们:

  • 使用示例数据生成器插入数据
  • 调用测试中的控制器操作
  • 计算正确答案
  • 如果返回的结果等于计算结果,则断言。

为了确保我们不会在测试和主要代码中重复出现错误,我们总是以不同的方式实施测试计算。

例如,如果在被测系统中有数据库查询,我们将获取所有数据并在内存中计算相应测试的结果。

我认为我们的方法有点像property-based testing。例如:

"a * a returns the correct value" >> {
  forAll { (a: Int, b: Int) =>
    a * b === (1 to b).fold(0) { (acc, b) => acc + a }
  }
}

另一种方法是为特定情况生成特定数据,并期望基于生成的数据得到固定结果,这些数据可能是手工计算的(而不是通过代码计算)。像这样:

"2 * 2 == 4" >> {
  2 * 2 === 4
}

"3 * 5 == 15" >> {
  3 * 5 === 15
}

// etc.
  

注意:我们的系统比这个简单的场景复杂得多

我们的方法存在的问题是,当我们的测试失败时,很难发现它是导致失败的测试或主要代码!

另一方面,我们必须编写更多测试来涵盖其他方法的所有数据场景,并且很难干。正如您在上面的测试示例中所看到的那样。

简而言之,我们有两种选择(我们知道):

  • 智能且复杂,但测试次数较少
  • 愚蠢而简单但测试次数更多

对于现实世界的应用程序推荐哪一个?为什么?

2 个答案:

答案 0 :(得分:4)

通过基于属性的测试,您需要从不同的角度测试系统,而不是以不同的方式为测试实现相同的功能。你想要测试不变量之类的东西,例如,如果你乘以2个正数,结果应该是正数。

虽然我认为基于财产的良好测试具有巨大的价值,但也很难提出这样的测试。所以,除非你认为你很了解你的域并且它足够稳定,否则我将从基于示例的测试开始。它们更易于编写和理解,这是您创建新内容时最重要的事情。

答案 1 :(得分:0)

这在所有情况下可能都不实用,但我认为最好的方法是使用两者。在开发期间使用简单的硬编码测试用例来涵盖所有情况,然后使用基于属性的测试来发现您忽略的情况。就像@driushkin所说的那样,基于属性的测试应该关注不变量。

使用基于属性的测试时,绝对使用最小化。这样,您就可以使用基于属性的测试来生成小而有趣的故障情况,然后您可以将其添加到您的硬编码测试套件中。

另外,一定要使用scoverage来测试覆盖率。这样很容易看出你的发电机/任意产生代表值。