【问题标题】:Display a reason for a failed QuickCheck property and handle exceptions in the tested function显示 QuickCheck 属性失败的原因并处理测试函数中的异常
【发布时间】:2012-11-22 13:41:00
【问题描述】:

我有一个 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”的属性 至于前面的例子?我想,对此可以使用whenFailwhenFail',但我还不了解QuickCheck 的内部结构。

【问题讨论】:

  • 是否有理由不为元素类型定义属性,而让 QuickCheck 一次测试一个元素?然后 QuickCheck 会告诉您失败的值。
  • 是的,我忘了提。在我的真实代码中,我通过在所有估值的详尽列表上进行比较来测试布尔公式的等价性。输出应该给我第一个估值,这些公式有偏差。
  • 我改变了问题,给出了一个更接近我真实代码的例子。

标签: haskell quickcheck


【解决方案1】:

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

无论如何,使用Control.Spoonprop可以改写如下:

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]

fromMaybe True . teaspoon 包裹 find 谓词具有 find 返回的效果 第一个元素要么满足谓词要么抛出异常。

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

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

【讨论】:

  • 我还是想知道有没有不使用unsafePerformIO的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-21
  • 2013-02-12
  • 2015-12-07
相关资源
最近更新 更多