3

我有一个 QuickCheck 属性测试一个功能f。该属性将函数映射到f某个列表xs并检查结果的某些元素属性。在失败的情况下,我想显示xs与此失败相关的元素。考虑以下属性:

prop x =
    printTestCase ("Failed for value " ++ show failure) $ isNothing failure
  where
    failure = fmap fst $ find (not . snd) $ map (\n -> (n, f x n == n)) [10..20]

这适用于实施

f = (+)

quickcheck prop输出

*** Failed! Falsifiable (after 2 tests):                  
1
Failed for value Just 10

但是,如果f抛出异常,即

f = undefined

然后quickcheck prop输出

*** Failed! Exception: 'Prelude.undefined' (after 1 test): 
()
Failed for value Exception thrown by generator: 'Prelude.undefined'

如何编写一个捕获第二个异常并返回“Just 0”的属性,就像前面的示例一样?我想,可以使用whenFailor whenFail',但我还不了解 QuickCheck 的内部结构。

4

1 回答 1

0

感谢#haskell 频道上的 aavogt,我找到了模块Control.Spoon,它提供了可以用来解决这个问题的勺子和茶匙功能。但是,我不知道使用这个包(它使用unsafePerformIO internally)有多安全。

无论如何,使用Control.Spoon,prop可以通过以下方式重写:

prop x =
    printTestCase ("Failed for value " ++ show pureFailure) $ isNothing excFailure
  where
    pureFailure = failure (fromMaybe True . teaspoon)
    excFailure = failure id
    failure g = fmap fst $ find (g . not . snd) $ map (\n -> (n, f x n == n)) [10..20]

将 find 谓词包裹起来fromMaybe True . teaspoon的效果是 find 返回满足谓词或抛出异常的第一个元素。

asteaspoon只能用于查看发生了异常,但不能用于查看异常,我 excFailure在这里使用,以便 QuickCheck 仍然可以看到异常。缺点是该发现需要进行两次评估。teaspoon仅评估为 WHNF,如果您需要深度评估来触发异常,请spoon改用。

teaspoon只捕获一些选择异常,这对我来说很好,因为我只关心未定义和不详尽的模式匹配。

于 2012-12-05T01:12:45.917 回答