条件QuickCheck属性

fre*_*low 12 haskell quickcheck

我为一个函数编写了一个QuickCheck属性,该函数将两个已排序的输入合并为一个已排序的输出:

prop_merge xs ys =
    if (sorted xs && sorted ys) then (sorted (merge xs ys)) else True
Run Code Online (Sandbox Code Playgroud)

也就是说,当输入被排序时,输出也被排序.它也可以写成:

prop_merge xs ys = not(sorted xs && sorted ys) || (sorted (merge xs ys))
Run Code Online (Sandbox Code Playgroud)

但我真的不喜欢这两个版本.QuickCheck中的"条件属性"有更好的语法吗?

ham*_*mar 30

您可以使用==>运算符将布尔条件附加到属性:

prop_merge xs ys = (sorted xs && sorted ys) ==> sorted (merge xs ys)
Run Code Online (Sandbox Code Playgroud)

这不仅是一种更好的语法,而且允许QuickCheck区分测试成功的测试用例和不满足前提条件的测试用例.在后一种情况下,不计算测试,QuickCheck生成新输入.

但是,在大多数输入不满足条件的情况下,这将导致测试运行得更慢,或者,如果丢弃了足够的输入,QuickCheck最终会放弃.由于随机列表不太可能被排序,因此上述示例很可能会发生这种情况:

> quickCheck (prop_merge :: [Int] -> [Int] -> Property)
*** Gave up! Passed only 15 tests.
Run Code Online (Sandbox Code Playgroud)

(注意,使用标准布尔运算符而不是使用==>,QuickCheck将提升所有传递的测试,当大多数测试由于前提条件失败而无用时)

因此,直接生成所需的测试用例通常要好得多.对于简单的情况,该Test.QuickCheck.Modifiers模块包含几个有用的新类型,它们可以修改输入的生成方式.例如,OrderedList修饰符将仅生成排序列表,因此我们可以将您的属性编写为:

prop_merge (Ordered xs) (Ordered ys) = sorted (merge xs ys)
Run Code Online (Sandbox Code Playgroud)

  • 我认为有必要明确指出`==>`不仅是一种更好的语法,而且允许QuickCheck区分测试成功的测试用例和不满足前提条件的测试用例.在后一种情况下,不计算测试,QuickCheck生成新输入.这使得QuickCheck能够为您提供"***Gave up!仅通过15次测试".如果前提条件是通过标准布尔运算符表示的,那么QuickCheck会提升所有传递的测试,当大多数测试由于前置条件失败而无用时. (2认同)