Comment afficher une raison d'une propriété de test a échoué avec quickcheck?
-
23-10-2019 - |
Question
Quelle est la meilleure pratique pour des raisons d'affichage pour un test de propriété a échoué lorsqu'il est testé par QuickCheck?
Prenons par exemple:
prop a b = res /= []
where
(res, reason) = checkCode a b
Ensuite, la séance pourrait ressembler à:
> quickCheck prop
Falsifiable, after 48 tests:
42
23
Mais pour le débogage, il serait vraiment pratique pour montrer la raison de l'échec dans le cadre du rapport quickcheck falsifable.
J'ai piraté comme ceci:
prop a b = if res /= [] then traceShow reason False else True
where
(res, reason) = checkCode a b
Y at-il une meilleure / ou plus agréable quickcheckish façon de le faire?
La solution
Je suppose que votre « raison » variable contient une sorte de données spécifiques de test sur ce qui a mal tourné. Vous pourriez plutôt retourner un « résultat », qui contient les deux succès / échec / conditions non valides et une chaîne expliquant ce qui a mal tourné. Propriétés que les résultats de retour sont gérés par QuickCheck exactement de la même manière que les propriétés qui reviennent Bool.
(modifier) ??comme ceci:
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 [] []
Notez qu'il est le « résultat » type défini dans Test.QuickCheck.Property vous voulez.
Il y a aussi quelques combinateurs définis dans Test.QuickCheck.Property qui vous aider à composer le résultat plutôt que d'appeler le constructeur directement, comme
prop_three :: Integer -> Property
prop_three n = printTestCase ("always fails: n = " ++ show n) False
Je suppose que ce serait mieux d'utiliser le style ceux-ci.
Autres conseils
Parce que QuickCheck vous donne les entrées à la fonction, et parce que le code en cours de test est pur (il est, non?), Vous pouvez simplement alimenter ces entrées à la fonction et obtenir le résultat. Ceci est plus souple, car avec ces entrées, vous pouvez également tester à plusieurs reprises avec quelques réglages à la fonction d'origine jusqu'à ce qu'il soit correct.
Ceci est ma solution (j'utilise counterexample
au lieu de printTestCase
depuis celui plus tard est maintenant dépréciée):
(<?>) :: (Testable p) => p -> String -> Property
(<?>) = flip (Test.QuickCheck.counterexample . ("Extra Info: " ++))
infixl 2 <?>
Utilisation:
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)
Alors, quand un test échoue, vous pouvez voir quelque chose comme:
*** Failed! Falsifiable, Falsifiable (after 2 tests):
1
-1
Extra Info: (1,1,0)
Vous pouvez également utiliser <?>
avec .&&.
, .||.
, ===
et ==>
etc.
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"
Cela fonctionne de la même manière que la réponse de Paul Johnson, mais est plus concis et robuste aux changements de 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