2011-11-19 5 views
14

Quando un valore non supera un test QuickCheck, mi piacerebbe usarlo per il debug. C'è un modo che io possa fare qualcosa di simile:Trova il valore che non è riuscito per quickcheck

let failValue = quickCheck' myTest 
in someStuff failValue 

Se il mio dati è stato in grado read poi ho potuto probabilmente incidere qualche modo per ottenere in da IO, ma non lo è.

risposta

9

Non ho trovato nulla nell'API QuickCheck per farlo in un modo carino, ma ecco qualcosa che ho hackerato usando l'API di QuickCheck monadica. Intercetta e registra gli input sulla proprietà in un IORef e presuppone che, in caso di errore, l'ultimo sia stato il colpevole e lo restituisca in un Just. Se il test è stato superato, il risultato è Nothing. Questo può probabilmente essere raffinato un po 'ma per semplici proprietà a un argomento dovrebbe fare il lavoro.

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

molto intelligente, grazie – Xodarap

+0

Questo piccolo trucco appena fatto la mia esperienza di debug Haskell molto meglio. Grazie –

2

Un modo sarebbe utilizzare il metodo sample', eseguire manualmente il test e trovare i valori in cui non riesce. Per esempio, testando una doppia funzione difettosa:

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 

L'unico problema è sample' genera solo 11 valori di test, che potrebbero non essere abbastanza per innescare il bug.