【问题标题】:How can I prevent QuickCheck from catching all exceptions?如何防止 QuickCheck 捕获所有异常?
【发布时间】:2012-03-03 21:48:01
【问题描述】:

QuickCheck 库似乎可以捕获测试属性时引发的所有异常。特别是,这种行为使我无法对整个 QuickCheck 计算设置时间限制。例如:

module QuickCheckTimeout where

import System.Timeout (timeout)
import Control.Concurrent (threadDelay)
import Test.QuickCheck (quickCheck, within, Property)
import Test.QuickCheck.Monadic (monadicIO, run, assert)

-- use threadDelay to simulate a slow computation
prop_slow_plus_zero_right_identity :: Int -> Property
prop_slow_plus_zero_right_identity i = monadicIO $ do
  run (threadDelay (100000 * i))
  assert (i + 0 == i)

runTests :: IO ()
runTests = do
  result <- timeout 3000000 (quickCheck prop_slow_plus_zero_right_identity)
  case result of
    Nothing -> putStrLn "timed out!"
    Just _  -> putStrLn "completed!"

因为 QuickCheck 捕获所有异常,timeout 中断:它实际上并没有中止计算!相反,QuickCheck 将属性视为失败,并尝试缩小导致失败的输入。然后这个收缩过程没有时间限制运行,导致计算使用的总时间超过规定的时间限制。

有人可能认为我可以使用 QuickCheck 的 within 组合器来限制计算时间。 (within 将属性视为失败,如果它没有在给定的时间限制内完成。)但是,within 并没有完全满足我的要求,因为 QuickCheck 仍然试图缩小导致失败的输入,一个可能需要很长时间的过程。 (另外对我有用的是within 的一个版本,它可以防止 QuickCheck 尝试将输入缩小到一个失败的属性,因为它没有在给定的时间限制内完成。)

如何防止 QuickCheck 捕获所有异常?

【问题讨论】:

    标签: testing haskell quickcheck


    【解决方案1】:

    由于 QuickCheck 在用户通过按 Ctrl+C 手动中断测试时执行正确的操作,因此您可以通过编写类似于timeout,但这会引发异步 UserInterrupt 异常,而不是自定义异常类型。

    这几乎是来自System.Timeout 的直接复制和粘贴工作:

    import Control.Concurrent
    import Control.Exception
    
    timeout' n f = do
        pid <- myThreadId
        bracket (forkIO (threadDelay n >> throwTo pid UserInterrupt))
                (killThread)
                (const f)
    

    使用这种方法,您必须使用quickCheckResult 并检查失败原因以检测测试是否超时。它似乎工作得很好:

    > runTests 
    *** Failed! Exception: 'user interrupt' (after 13 tests):  
    16
    

    【讨论】:

    • 赞成,因为该解决方案解决了特定的用例(即对整个 QuickCheck 计算设置时间限制)。仔细研究源代码,看起来 QuickCheck 是硬连线来专门处理 UserInterrupt 异常的。不幸的是,这个解决方案并没有完全回答我的问题:QuickCheck 仍然吞下除 UserInterrupt 之外的所有内容!
    【解决方案2】:
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-26
    • 2023-03-31
    • 1970-01-01
    • 2018-07-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多