15

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

prop_merge xs ys =
    if (sorted xs && sorted ys) then (sorted (merge xs ys)) else True

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

prop_merge xs ys = not(sorted xs && sorted ys) || (sorted (merge xs ys))

但我真的不喜欢这两个版本。QuickCheck 中的“条件属性”是否有更好的语法?

4

1 回答 1

33

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

prop_merge xs ys = (sorted xs && sorted ys) ==> sorted (merge xs ys)

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

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

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

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

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

prop_merge (Ordered xs) (Ordered ys) = sorted (merge xs ys)
于 2012-10-14T18:05:45.890 回答