2011-11-19 93 views
14

當一個值未通過QuickCheck'd測試時,我想用它進行調試。有什麼辦法,我可以這樣做:找到失敗的值進行快速檢查

let failValue = quickCheck' myTest 
in someStuff failValue 

如果我的數據是read能夠那麼我或許可以破解一些方法來從IO得到它,但它不是。

回答

9

我在QuickCheck API中找不到任何東西來以一種很好的方式做到這一點,但這裏是我使用monadic QuickCheck API一起入侵的東西。它攔截並記錄到IORef的財產的輸入,並假設如果失敗,最後一個是罪魁禍首,並返回Just。如果測試通過,結果是Nothing。這可能會稍微改進一點,但對於簡單的單參數屬性,它應該完成這項工作。

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" 
+0

非常聰明,謝謝 – Xodarap

+0

這個小竅門讓我的Haskell調試體驗好了很多。謝謝 –

2

一種方法是使用sample'方法,手動運行測試並找到失敗的值。例如,當測試有故障的雙重功能:

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個測試值,即可能不足以觸發錯誤。