[英]How can I prevent QuickCheck from catching all exceptions?
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将属性视为失败,并尝试缩小导致失败的输入。 然后,该缩小过程不会以时间限制运行,导致计算使用的总时间超过规定的时间限制。
有人可能会认为我可以within
组合器中使用QuickCheck来限制计算时间。 ( within
治疗的属性,如果它没有在给定的时间限制内完成混不下去。)然而, within
并不完全做我想做的,因为快速检查仍试图收缩导致失败的输入,这个过程可能花了太长时间。 (对我来说可能的替代方案是within
版本阻止QuickCheck尝试将输入缩小到失败的属性,因为它没有在给定的时间限制内完成。)
如何防止QuickCheck捕获所有异常?
由于当用户通过按Ctrl + C手动中断测试时,QuickCheck会做正确的事情,您可以通过编写类似于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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.