7

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 はプロパティが失敗したものとして扱い、失敗の原因となった入力を縮小しようとします。この縮小プロセスは時間制限付きで実行されないため、計算に使用される合計時間が規定の時間制限を超えます。

withinQuickCheck のコンビネータを使用して計算時間を制限できると考える人もいるかもしれません。(within指定された制限時間内に終了しない場合、プロパティは失敗したものとして扱います。)ただし、withinQuickCheckは失敗の原因となった入力を縮小しようとするため、プロセスに時間がかかる可能性があるため、私が望むことはできません。長すぎる。(代わりに機能するwithinのは、指定された制限時間内に終了しなかったために失敗したプロパティへの入力を QuickCheck が縮小しようとするのを防ぐバージョンです。)

QuickCheck がすべての例外をキャッチしないようにするにはどうすればよいですか?

4

2 に答える 2

4

Ctrlユーザーが+を押して手動でテストを中断すると、QuickCheck は正しいことを行うため、 の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
于 2012-03-04T13:02:37.510 に答える
1

多分chasingbottomsパッケージは役に立つでしょうか? http://hackage.haskell.org/packages/archive/ChasingBottoms/1.3.0.3/doc/html/Test-ChasingBottoms-TimeOut.html

于 2012-03-04T07:07:58.960 に答える