如果我已经练习基于实例的测试,为什么我真的应该使用基于属性的测试?

时间:2015-06-22 18:51:37

标签: unit-testing testing tdd property-based-testing

有一点需要注意的是,一些开发人员认为TDD与基于实例的测试有关,可能缺少每一个有效的输入处理。

让我们举一个简单的例子,开发人员可以争辩说:

  

制作一个添加两个数字的程序。

鲍勃,开发人员开始编写第一个测试:
给定1 + 3,结果为4 实施: def add(x:Int,y:Int)= 4
很好,它过去了。

现在进行第二次测试:
给定2 + 2,结果为4 。 实现仍然相同: def add(x:Int,y:Int)= 4

所以其他开发者会来告诉他:

“现在你看到鲍勃,基于实例的测试对你的可怜的2个例子是不够的! 您没有测试每个输出并查看您的实际实现,对于其结果与4不同的其他输入,它将失败! 现在,听取我们的意见,开始编写一些基于属性的测试,以涵盖所有有效的输入 因此,让我们从交换性测试,关联性等开始,这些是特定于添加的属性!“

但是但是......鲍勃的TDD练习真的很糟糕! 实际上,他想要应用三角测量,但他写了一个已经成功的测试,因为实现不得改变!

要导致三角测量,应该编写一个失败的测试。 三角测量是TDD实践的关键之一 它允许主要步骤:重构,因为您应该管理两条导致2个不同结果的路径!

=>只要测试具体化,由于重构,代码变得更加通用。

所以我的问题是:
如果我们通过良好的三角测量实践严格的TDD,使用基于属性的测试的真正好处是什么,断言99%的情况下已经由良好TDD覆盖的不变量? 实际上,假设开发人员具有良好的智商并构建有意义的实现;)

我的例子取自those slides

2 个答案:

答案 0 :(得分:4)

基于属性的测试非常有用,当边缘情况很难找到,或者有很多这样的程序员很容易错过。我使用它时,例如当我实施hirschberg的算法时。没有明显的方法可以将算法划分为更小,更简单,易于TDD测试的部分。并且很难手工制作涵盖所有可能的算法路径的输入。最好的方法是生成大量不同的输入以覆盖所有路径。当自动检查发现错误时,将该特定输入添加到回归测试

答案 1 :(得分:1)

如果您练习 TDD ,您知道这是一种思考和设计的方式而不是测试。

TDD起源于增量,主要是基于状态的单元测试。然后 交互式(即, mockist-style 伦敦风格的)TDD改变了我们对代码设计代码的思考方式。

基于属性的 TDD也有机会改变我们设计代码的方式。我们使用属性而不是生成示例来推动我们的设计。这导致更少的测试更易于维护,并具有更好的测试覆盖率。

另一方面,它比基于TDD的示例更难,需要更多思考。