Domanda

Qual è la migliore pratica per motivi di visualizzazione per un test di proprietà fallito quando viene testato tramite QuickCheck?

Si consideri ad esempio:

prop a b = res /= []
   where
      (res, reason) = checkCode a b

Poi l'una sessione potrebbe essere simile:

> quickCheck prop
Falsifiable, after 48 tests:
42
23

Ma per il debug sarebbe davvero comodo per mostrare il motivo per il fallimento come parte della relazione falsifable QuickCheck.

ho violato in questo modo:

prop a b = if res /= [] then traceShow reason False else True
   where
      (res, reason) = checkCode a b

è che c'è un modo migliore / più o più quickcheckish per farlo?

È stato utile?

Soluzione

Presumo che la variabile "ragione" contiene un qualche tipo di dati di test specifici su cosa è andato storto. Si potrebbe invece restituire un "risultato", che contiene sia il successo / fallimento / condizioni non valide e una stringa che spiega cosa è andato storto. Proprietà che i risultati di ritorno sono gestite da QuickCheck esattamente nello stesso modo in cui le proprietà che restituiscono Bool.

(Modifica) Ti piace questa:

module QtTest where 

import Test.QuickCheck
import Test.QuickCheck.Property as P


-- Always return success
prop_one :: Integer -> P.Result
prop_one _ = MkResult (Just True) True "always succeeds" False [] []


-- Always return failure
prop_two :: Integer -> P.Result
prop_two n = MkResult (Just False) True ("always fails: n = " ++ show n) False [] []

Si noti che è il "risultato" tipo definito nel Test.QuickCheck.Property si desidera.

Ci sono anche alcuni combinatori definiti in Test.QuickCheck.Property che consente di inquadrare meglio il risultato piuttosto che chiamare direttamente la funzione di costruzione, come ad esempio

prop_three :: Integer -> Property
prop_three n = printTestCase ("always fails: n = " ++ show n) False

Credo che sarebbe stato lo stile meglio utilizzare quelli.

Altri suggerimenti

A causa QuickCheck ti dà gli input alla funzione, e perché il codice in prova è pura (che è, giusto?), Si può solo alimentare gli ingressi alla funzione e ottenere il risultato. Questo è più flessibile, perché con gli ingressi si possono anche ripetutamente test con modifiche alla funzione originaria fino a quando non è corretto.

Questa è la mia soluzione (io uso counterexample invece di printTestCase dopo quella successiva è deprecata ora):

(<?>) :: (Testable p) => p -> String -> Property
(<?>) = flip (Test.QuickCheck.counterexample . ("Extra Info: " ++))
infixl 2 <?>

Utilizzo:

main :: IO ()
main = hspec $ do
  describe "math" $ do
    prop "sum-of-square-le-square-of-sum" $ do
      \(x :: Int) (y :: Int) ->
        x * x + y * y <= (x + y) * (x + y) <?> show (x * x, y * y, x + y)

Così, quando un banco di prova riesce, è possibile vedere qualcosa di simile:

   *** Failed! Falsifiable, Falsifiable (after 2 tests):
   1
   -1
   Extra Info: (1,1,0)

È anche possibile utilizzare <?> insieme .&&., .||., === e ==> ecc.

  describe "math" $ do
    prop "sum-of-square-le-square-of-sum" $ do
      \(x :: Int) (y :: Int) ->
        x * x + y * y <= (x + y) * (x + y) <?> show (x * x, y * y, x + y) .||. (1==0) <?> "haha"

Questo funziona nello stesso modo come la risposta di Paul Johnson, ma è più conciso e robusto alle variazioni di MkResult:

import Test.QuickCheck.Property (succeeded, failed, reason)

prop a b =
  if res /= []
    then succeeded
    else failed { reason = reason }
   where
      (res, reason) = checkCode a b
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top