2012-03-03 5 views
7

QuickCheckライブラリは、プロパティのテスト時にスローされるすべての例外をキャッチしているようです。特に、この動作により、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は、QuickCheckが失敗の原因となった入力を縮小しようとしているので、私が望むことをしていません。あまりにも長くかかる。 (私の代わりに働くことができるのはwithinなので、QuickCheckは指定された制限時間内に終了しなかったために失敗したプロパティに入力を縮小しようとしません)。

QuickCheckがキャッチしないようにする方法すべての例外は?

答えて

4

ユーザーが手動で押してテストを中断する場合QuickCheckは正しいことをやっているのでCtrlキー + C、あなたがtimeoutに似た何かを書き込むことによってこの問題を回避することができるかもしれませんが、それはasynchroneous 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 
+0

このソリューションは、特定のユースケースに対応している(つまり、QuickCheckの計算全体に時間制限を設定しているため)ことをお勧めします。ソースコードを見てみると、QuickCheckはUserInterrupt例外を特別に扱うように配線されているようです。 残念ながら、このソリューションは私の質問にはあまり答えていません.QuickCheckはまだUserInterrupt以外のすべてを呑み込んでいます! –

関連する問題