Haskell Language
Snelle check
Zoeken…
Eigendom verklaren
In het eenvoudigste geval is een eigenschap een functie die een Bool
retourneert.
prop_reverseDoesNotChangeLength xs = length (reverse xs) == length xs
Een eigenschap verklaart een invariant op hoog niveau van een programma. De QuickCheck-testloper zal de functie evalueren met 100 willekeurige ingangen en controleren of het resultaat altijd True
.
Volgens afspraak hebben functies die eigenschappen hebben namen die beginnen met prop_
.
Een enkele eigenschap controleren
De quickCheck
functie test een eigenschap op 100 willekeurige ingangen.
ghci> quickCheck prop_reverseDoesNotChangeLength
+++ OK, passed 100 tests.
Als een eigenschap mislukt voor bepaalde invoer, drukt quickCheck
een tegenvoorbeeld af.
prop_reverseIsAlwaysEmpty xs = reverse xs == [] -- plainly not true for all xs
ghci> quickCheck prop_reverseIsAlwaysEmpty
*** Failed! Falsifiable (after 2 tests):
[()]
Alle eigenschappen in een bestand controleren
quickCheckAll
is een Template Haskell-helper die alle definities in het huidige bestand vindt waarvan de naam begint met prop_
en deze test.
{-# LANGUAGE TemplateHaskell #-}
import Test.QuickCheck (quickCheckAll)
import Data.List (sort)
idempotent :: Eq a => (a -> a) -> a -> Bool
idempotent f x = f (f x) == f x
prop_sortIdempotent = idempotent sort
-- does not begin with prop_, will not be picked up by the test runner
sortDoesNotChangeLength xs = length (sort xs) == length xs
return []
main = $quickCheckAll
Merk op dat de return []
regel is vereist. Het maakt definities tekstueel boven die regel zichtbaar voor Template Haskell.
$ runhaskell QuickCheckAllExample.hs
=== prop_sortIdempotent from tree.hs:7 ===
+++ OK, passed 100 tests.
Willekeurig genereren van gegevens voor aangepaste typen
De klasse Arbitrary
is voor typen die willekeurig door QuickCheck kunnen worden gegenereerd.
De minimale implementatie van Arbitrary
is de arbitrary
methode, die in de Gen
monade wordt uitgevoerd om een willekeurige waarde te produceren.
Hier is een voorbeeld van Arbitrary
voor het volgende gegevenstype van niet-lege lijsten.
import Test.QuickCheck.Arbitrary (Arbitrary(..))
import Test.QuickCheck.Gen (oneof)
import Control.Applicative ((<$>), (<*>))
data NonEmpty a = End a | Cons a (NonEmpty a)
instance Arbitrary a => Arbitrary (NonEmpty a) where
arbitrary = oneof [ -- randomly select one of the cases from the list
End <$> arbitrary, -- call a's instance of Arbitrary
Cons <$>
arbitrary <*> -- call a's instance of Arbitrary
arbitrary -- recursively call NonEmpty's instance of Arbitrary
]
Implicatie (==>) gebruiken om eigenschappen met randvoorwaarden te controleren
prop_evenNumberPlusOneIsOdd :: Integer -> Property
prop_evenNumberPlusOneIsOdd x = even x ==> odd (x + 1)
Als u wilt controleren of een eigenschap vasthoudt gegeven een voorwaarde, kunt u de operator ==>
gebruiken. Let op: als het zeer onwaarschijnlijk is dat willekeurige invoer overeenkomt met de voorwaarde, kan QuickCheck vroeg opgeven.
prop_overlySpecific x y = x == 0 ==> x * y == 0
ghci> quickCheck prop_overlySpecific
*** Gave up! Passed only 31 tests.
Beperking van de grootte van testgegevens
Het kan moeilijk zijn om functies met een slechte asymptotische complexiteit te testen met behulp van quickcheck, omdat de willekeurige invoer meestal niet aan de grootte gebonden is. Door een bovengrens toe te voegen aan de grootte van de invoer, kunnen we deze dure functies nog steeds testen.
import Data.List(permutations)
import Test.QuickCheck
longRunningFunction :: [a] -> Int
longRunningFunction xs = length (permutations xs)
factorial :: Integral a => a -> a
factorial n = product [1..n]
prop_numberOfPermutations xs =
longRunningFunction xs == factorial (length xs)
ghci> quickCheckWith (stdArgs { maxSize = 10}) prop_numberOfPermutations
Door quickCheckWith
met een aangepaste versie van stdArgs
we de grootte van de ingangen beperken tot maximaal 10. In dit geval, omdat we lijsten genereren, betekent dit dat we lijsten tot maximaal 10 genereren. Onze permutatiefunctie werkt niet het duurt te lang voordat deze korte lijsten zijn uitgevoerd, maar we kunnen er nog steeds redelijk zeker van zijn dat onze definitie correct is.