对于Haskell的QuickCheck,什么是收缩?

时间:2013-06-06 17:33:59

标签: haskell quickcheck

我正在学习QuickCheck> = 2.6的绳索,但我不明白收缩是什么。从type signature收缩看起来更像是展开!请照亮我:))

2 个答案:

答案 0 :(得分:61)

当QuickCheck发现违反属性的输入时,它会首先尝试查找同样违反该属性的较小输入,以便为开发人员提供有关失败性质的更好信息。

当然,“小”意味着什么取决于所讨论的数据类型;对于QuickCheck,它是来自shrink函数的任何内容。

最好在QuickCheck会话中解释:

Prelude Test.QuickCheck> let prop l = all (/= 5) l
Prelude Test.QuickCheck> quickCheck prop
*** Failed! Falsifiable (after 10 tests and 2 shrinks):    
[5]

所以这里QuickCheck能够给出最小的反例 - 但是从评论来看,它首先考虑了更大的列表,然后使用shrink来减少它。要仔细了解正在发生的事情,我们使用verboseCheck

Prelude Test.QuickCheck> verboseCheck prop
Passed:  
[]
Passed: 
[0]
Passed:  
[-2,1]
Passed:  
[-2,2,-2]
Passed:  
[-4]
Failed:  
[-1,-2,5,4,2]
*** Failed! Passed:                       
[]
Failed:                                       
[5,4,2]
Passed:                                    
[]
Passed:                                       
[4,2]
Failed:                                       
[5,2]
Passed:                                     
[]
Passed:                                       
[2]
Failed:                                       
[5]
Passed:                                     
[]
Passed:                                       
[0]
Passed:                                       
[3]
Passed:                                       
[4]
Falsifiable (after 6 tests and 3 shrinks):    
[5]

QuickCheck尝试命题所包含的几个列表,然后找到[-1,-2,5,4,2]。现在它通过尝试它的子列表来减少列表。您可以在GHCi中说服自己shrink [-1,-2,5,4,2] == [[],[5,4,2],[-1,-2,2],...,第二个条目是第一个仍未通过测试的条目。然后,QuickCheck将继续并进一步缩小:shrink [5,4,2] == [[],[4,2],[5,2],...,以及shrink [5,2] [[],[2],[5],...。最后,它会尝试进一步缩小[5],但shrink [5] == [[],[0],[3],[4]]都没有使命题失败,因此最终的计数示例为[5]

答案 1 :(得分:10)

单个shrink是逐步降低某些Arbitrary测试用例的复杂性(“立即收缩”)。这可能类似于2 -> 11:[] -> []。对于更复杂的类型,可能有多种方法可以“逐步缩小”类型,因此您可以在列表中指定所有类型。

例如,通过删除任何一个叶子可能会缩小树木,因此如果有n个叶子,则shrink会生成一个长度为n的列表。