When a value fails a QuickCheck'd test, I'd like to use it for debugging. Is there any way I can do something like:
let failValue = quickCheck' myTest
in someStuff failValue
If my data was read
able then I could probably hack some way to get it in from IO, but it's not.
I couldn't find anything in the QuickCheck API to do this in a nice way, but here's something I hacked together using the monadic QuickCheck API. It intercepts and logs the inputs to your property in an IORef
, and assumes that if it failed, the last one was the culprit and returns it in a Just
. If the test passed, the result is Nothing
. This can probably be refined a bit but for simple one-argument properties it should do the job.
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"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With