ある値が QuickCheck のテストに失敗した場合、それをデバッグに使用したいと考えています。次のようなことができる方法はありますか?
let failValue = quickCheck' myTest
in someStuff failValue
私のデータが可能であれば、read何らかの方法でハッキングして IO からデータを取得できたかもしれませんが、そうではありません。
ある値が QuickCheck のテストに失敗した場合、それをデバッグに使用したいと考えています。次のようなことができる方法はありますか?
let failValue = quickCheck' myTest
in someStuff failValue
私のデータが可能であれば、read何らかの方法でハッキングして IO からデータを取得できたかもしれませんが、そうではありません。
QuickCheck API には、これを適切に行う方法は何も見つかりませんでしたが、モナディックな QuickCheck API を使用して一緒にハッキングしたものを次に示します。プロパティへの入力を傍受して でログに記録し、IORef失敗した場合は最後の入力が原因であると想定し、 で返しますJust。テストに合格した場合、結果はNothingです。これはおそらく少し洗練される可能性がありますが、引数が 1 つの単純なプロパティの場合は、これで十分です。
import Control.Monad
import Data.IORef
import Test.QuickCheck
import Test.QuickCheck.Monadic
prop_failIfZero :: Int -> Bool
prop_failIfZero n = n /= 0
quickCheck' :: (Arbitrary a, Show a) => (a -> Bool) -> IO (Maybe a)
quickCheck' prop = do input <- newIORef Nothing
result <- quickCheckWithResult args (logInput input prop)
case result of
Failure {} -> readIORef input
_ -> return Nothing
where
logInput input prop x = monadicIO $ do run $ writeIORef input (Just x)
assert (prop x)
args = stdArgs { chatty = False }
main = do failed <- quickCheck' prop_failIfZero
case failed of
Just x -> putStrLn $ "The input that failed was: " ++ show x
Nothing -> putStrLn "The test passed"
1 つの方法は、サンプルの方法を使用して手動でテストを実行し、失敗した値を見つけることです。たとえば、問題のある double 関数をテストします。
import Test.QuickCheck
double :: Int -> Int
double x | x < 10 = 2 * x
| otherwise = 13
doubleTest :: Int -> Bool
doubleTest x = x + x == double x
tester :: IO ()
tester = do
values <- sample' arbitrary
let failedValues = filter (not . doubleTest) values
print failedValues
唯一の問題はsample'、11 個のテスト値しか生成しないことです。これでは、バグを引き起こすには十分ではない可能性があります。