Quickcheck Funktionale Programmierung Fallstudie Quickcheck D. Rösner Institut für Wissens- und Sprachverarbeitung Fakultät für Informatik Otto-von-Guericke Universität Magdeburg c Sommer 2010, 18. Mai 2010, 2010 D.Rösner D. Rösner FP 2010 . . . 1 Quickcheck Gliederung 1 Quickcheck Einführung Generatoren Testen Weitere Aspekte D. Rösner FP 2010 . . . 2 Quickcheck Einführung Generatoren Testen Weitere Aspekte Gliederung 1 Quickcheck Einführung Generatoren Testen Weitere Aspekte D. Rösner FP 2010 . . . 3 Quickcheck Einführung Generatoren Testen Weitere Aspekte Fallstudie: Testen von Haskell-Programmen Programm QuickCheck Quelle: http://www.cs.chalmers.se/~rjmh/QuickCheck D. Rösner FP 2010 . . . 4 Quickcheck Einführung Generatoren Testen Weitere Aspekte Fallstudie: Testen von Haskell-Programmen Programm QuickCheck Quelle: http://www.cs.chalmers.se/~rjmh/QuickCheck Grundidee: Benutzer definiert Eigenschaften, die ein Programm erfüllen soll D. Rösner FP 2010 . . . 4 Quickcheck Einführung Generatoren Testen Weitere Aspekte Fallstudie: Testen von Haskell-Programmen Programm QuickCheck Quelle: http://www.cs.chalmers.se/~rjmh/QuickCheck Grundidee: Benutzer definiert Eigenschaften, die ein Programm erfüllen soll diese Eigenschaften werden dann an einer grossen Zahl automatisch generierter Testfälle überprüft D. Rösner FP 2010 . . . 4 Quickcheck Einführung Generatoren Testen Weitere Aspekte Fallstudie: QuickCheck Beispiel: Definition einer Eigenschaft prop_RevRev xs = reverse(reverse xs) == xs where types = xs::[Int] D. Rösner FP 2010 . . . 5 Quickcheck Einführung Generatoren Testen Weitere Aspekte Fallstudie: QuickCheck Beispiel: Definition einer Eigenschaft prop_RevRev xs = reverse(reverse xs) == xs where types = xs::[Int] Testen einer Eigenschaft QuickCheckTest> quickCheck prop_RevRev OK, passed 100 tests. D. Rösner FP 2010 . . . 5 Quickcheck Einführung Generatoren Testen Weitere Aspekte Fallstudie: QuickCheck Beispiel: Definition einer Eigenschaft prop_RevId xs = reverse xs == xs where types = xs::[Int] Testen und Falsifizieren einer Eigenschaft QuickCheckTest> quickCheck prop_RevId Falsifiable, after 4 tests: [-4,-3,4] D. Rösner FP 2010 . . . 6 Quickcheck Einführung Generatoren Testen Weitere Aspekte Fallstudie: QuickCheck Beispiel: ausführliches Ablaufprotokoll: QuickCheckTest> verboseCheck prop_RevId 0: [] 1: [-1] 2: [] 3: [0,-4,0] 4: [1,0] Falsifiable, after 4 tests: [1,0] D. Rösner FP 2010 . . . 7 Quickcheck Einführung Generatoren Testen Weitere Aspekte Gliederung 1 Quickcheck Einführung Generatoren Testen Weitere Aspekte D. Rösner FP 2010 . . . 8 Quickcheck Einführung Generatoren Testen Weitere Aspekte Fallstudie: QuickCheck zentral sind Generatoren für Testdaten D. Rösner FP 2010 . . . 9 Quickcheck Einführung Generatoren Testen Weitere Aspekte Fallstudie: QuickCheck zentral sind Generatoren für Testdaten Typ: newtype Gen a = Gen (Int -> StdGen -> a) D. Rösner FP 2010 . . . 9 Quickcheck Einführung Generatoren Testen Weitere Aspekte Fallstudie: QuickCheck zentral sind Generatoren für Testdaten Typ: newtype Gen a = Gen (Int -> StdGen -> a) Typ Gen ist Funktor und Monade D. Rösner FP 2010 . . . 9 Quickcheck Einführung Generatoren Testen Weitere Aspekte Fallstudie: QuickCheck Definition als Funktor: instance Functor Gen where fmap f m = m >>= return . f D. Rösner FP 2010 . . . 10 Quickcheck Einführung Generatoren Testen Weitere Aspekte Fallstudie: QuickCheck Definition als Funktor: instance Functor Gen where fmap f m = m >>= return . f Definition als Monade: instance Monad Gen where return a = Gen (\n r -> a) Gen m >>= k = Gen (\n r0 -> let (r1,r2) = split r0 Gen m’ = k (m n r1) in m’ n r2) D. Rösner FP 2010 . . . 10 Quickcheck Einführung Generatoren Testen Weitere Aspekte Fallstudie: QuickCheck zentrale Funktion: choose :: Random a => (a, a) -> Gen a choose bounds = (fst . randomR bounds) ‘fmap‘ rand rand :: Gen StdGen rand = Gen (\n r -> r) D. Rösner FP 2010 . . . 11 Quickcheck Einführung Generatoren Testen Weitere Aspekte Fallstudie: QuickCheck Kombinatoren für Generatoren: Auswahl aus einer Liste von Generatoren oneof :: [Gen a] -> Gen a oneof gens = elements gens >>= id D. Rösner FP 2010 . . . 12 Quickcheck Einführung Generatoren Testen Weitere Aspekte Fallstudie: QuickCheck Kombinatoren für Generatoren: Auswahl aus einer Liste von Generatoren oneof :: [Gen a] -> Gen a oneof gens = elements gens >>= id Beispiel: oneof [return True, return False] D. Rösner FP 2010 . . . 12 Quickcheck Einführung Generatoren Testen Weitere Aspekte Fallstudie: QuickCheck Kombinatoren für Generatoren: Beeinflussung der Verteilung: frequency :: [(Int, Gen a)] -> Gen a frequency xs = choose (1, tot) >>= (‘pick‘ xs) where tot = sum (map fst xs) pick n ((k,x):xs) | n <= k = x | otherwise = pick (n-k) xs D. Rösner FP 2010 . . . 13 Quickcheck Einführung Generatoren Testen Weitere Aspekte Fallstudie: QuickCheck Kombinatoren für Generatoren: Beeinflussung der Verteilung: frequency :: [(Int, Gen a)] -> Gen a frequency xs = choose (1, tot) >>= (‘pick‘ xs) where tot = sum (map fst xs) pick n ((k,x):xs) | n <= k = x | otherwise = pick (n-k) xs Beispiel: frequency [(2,return True), (1,return False)] D. Rösner FP 2010 . . . 13 Quickcheck Einführung Generatoren Testen Weitere Aspekte Fallstudie: QuickCheck vordefinierte Generatoren für zahlreiche Typen Überladen der Methoden der Klasse Arbitrary class Arbitrary a where arbitrary :: Gen a coarbitrary :: a -> Gen b -> Gen b D. Rösner FP 2010 . . . 14 Quickcheck Einführung Generatoren Testen Weitere Aspekte Fallstudie: QuickCheck vordefinierte Generatoren für zahlreiche Typen Überladen der Methoden der Klasse Arbitrary class Arbitrary a where arbitrary :: Gen a coarbitrary :: a -> Gen b -> Gen b arbitrary . . . für zufällige Werte des Typs a D. Rösner FP 2010 . . . 14 Quickcheck Einführung Generatoren Testen Weitere Aspekte Fallstudie: QuickCheck vordefinierte Generatoren für zahlreiche Typen Überladen der Methoden der Klasse Arbitrary class Arbitrary a where arbitrary :: Gen a coarbitrary :: a -> Gen b -> Gen b arbitrary . . . für zufällige Werte des Typs a coarbitrary . . . für zufällige Funktionen des Typs a-> b D. Rösner FP 2010 . . . 14 Quickcheck Einführung Generatoren Testen Weitere Aspekte Fallstudie: QuickCheck vordefinierte Generatoren für zahlreiche Typen Beispiel: Typ Arbitrary Int instance Arbitrary Int where arbitrary = sized $ \n -> choose (-n,n) coarbitrary n = variant (if n >= 0 then 2*n else 2*(-n) + 1) D. Rösner FP 2010 . . . 15 Quickcheck Einführung Generatoren Testen Weitere Aspekte Fallstudie: QuickCheck vordefinierte Generatoren für zahlreiche Typen Beispiel: Typ Arbitrary (a, b): instance (Arbitrary a, Arbitrary b) => Arbitrary (a, b) where arbitrary = liftM2 (,) arbitrary arbitrary coarbitrary (a, b) = coarbitrary a . coarbitrary b D. Rösner FP 2010 . . . 16 Quickcheck Einführung Generatoren Testen Weitere Aspekte Fallstudie: QuickCheck vordefinierte Generatoren für zahlreiche Typen Beispiel: Typ Arbitrary (a, b): instance (Arbitrary a, Arbitrary b) => Arbitrary (a, b) where arbitrary = liftM2 (,) arbitrary arbitrary coarbitrary (a, b) = coarbitrary a . coarbitrary b verwendet wird hier die monadische Funktion liftM2 liftM2 :: (Monad m) => (a -> b -> c) -> (m a -> m b -> m c) liftM2 f = \a b -> do { a’ <- a; b’ <- b; return (f a’ b’) } D. Rösner FP 2010 . . . 16 Quickcheck Einführung Generatoren Testen Weitere Aspekte Gliederung 1 Quickcheck Einführung Generatoren Testen Weitere Aspekte D. Rösner FP 2010 . . . 17 Quickcheck Einführung Generatoren Testen Weitere Aspekte Fallstudie: Testen von Haskell-Programmen Programm QuickCheck erlaubt Testen bedingter Eigenschaften D. Rösner FP 2010 . . . 18 Quickcheck Einführung Generatoren Testen Weitere Aspekte Fallstudie: Testen von Haskell-Programmen Programm QuickCheck erlaubt Testen bedingter Eigenschaften Testen quantifizierter Eigenschaften D. Rösner FP 2010 . . . 18 Quickcheck Einführung Generatoren Testen Weitere Aspekte Fallstudie: Testen von Haskell-Programmen Programm QuickCheck erlaubt Testen bedingter Eigenschaften Testen quantifizierter Eigenschaften Steuerung der Verteilung der Testfälle D. Rösner FP 2010 . . . 18 Quickcheck Einführung Generatoren Testen Weitere Aspekte Fallstudie: Testen von Haskell-Programmen Programm QuickCheck erlaubt Testen bedingter Eigenschaften Testen quantifizierter Eigenschaften Steuerung der Verteilung der Testfälle Klassifizieren und Zählen von Testfällen D. Rösner FP 2010 . . . 18 Quickcheck Einführung Generatoren Testen Weitere Aspekte Fallstudie: Testen von Haskell-Programmen Programm QuickCheck erlaubt Testen bedingter Eigenschaften Testen quantifizierter Eigenschaften Steuerung der Verteilung der Testfälle Klassifizieren und Zählen von Testfällen Sammeln von Datenwerten D. Rösner FP 2010 . . . 18 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: Testen bedingter Eigenschaften Eigenschaft können die Form haben <condition> ==> <property> D. Rösner FP 2010 . . . 19 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: Testen bedingter Eigenschaften Eigenschaft können die Form haben <condition> ==> <property> eine solche Eigenschaft gilt genau dann, wenn die Eigenschaft nach dem ==> immer gilt, wenn die <condition> gilt D. Rösner FP 2010 . . . 19 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: Testen bedingter Eigenschaften Eigenschaft können die Form haben <condition> ==> <property> eine solche Eigenschaft gilt genau dann, wenn die Eigenschaft nach dem ==> immer gilt, wenn die <condition> gilt beim Testen werden nur Testfälle betrachtet, welche die <condition> erfüllen ; falls nach einer vorgegebenen Anzahl von Versuchen (derzeit: 1000) noch keine 100 Testfälle gefunden, wird beendet und Meldung ausgegeben wie Arguments exhausted after 97 test. D. Rösner FP 2010 . . . 19 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: Testen quantifizierter Eigenschaften Eigenschaften können die Form haben forAll <generator> $ \<pattern> -> <property> D. Rösner FP 2010 . . . 20 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: Testen quantifizierter Eigenschaften Eigenschaften können die Form haben forAll <generator> $ \<pattern> -> <property> Beispiel: prop_Insert2 x = forAll orderedList $ \xs -> ordered (insert x xs) where types = x::Int D. Rösner FP 2010 . . . 20 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: Testen quantifizierter Eigenschaften Eigenschaften können die Form haben forAll <generator> $ \<pattern> -> <property> Beispiel: prop_Insert2 x = forAll orderedList $ \xs -> ordered (insert x xs) where types = x::Int das erste Argument des forAll ist ein Testdatengenerator D. Rösner FP 2010 . . . 20 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: Testen quantifizierter Eigenschaften Eigenschaften können die Form haben forAll <generator> $ \<pattern> -> <property> Beispiel: prop_Insert2 x = forAll orderedList $ \xs -> ordered (insert x xs) where types = x::Int das erste Argument des forAll ist ein Testdatengenerator mit solchen speziellen Generatoren lässt sich die Verteilung der Testdaten besser kontrollieren als durch Filtern D. Rösner FP 2010 . . . 20 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: Zählen trivialer Fälle Eigenschaften können die Form haben <condition> ‘trivial‘ <property> D. Rösner FP 2010 . . . 21 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: Zählen trivialer Fälle Eigenschaften können die Form haben <condition> ‘trivial‘ <property> Beispiel: prop_Insert x xs = ordered xs ==> null xs ‘trivial‘ ordered (insert x xs) where types = x::Int D. Rösner FP 2010 . . . 21 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: Zählen trivialer Fälle Eigenschaften können die Form haben <condition> ‘trivial‘ <property> Beispiel: prop_Insert x xs = ordered xs ==> null xs ‘trivial‘ ordered (insert x xs) where types = x::Int Testfälle, für die Bedingung zutrifft, werden als trivial klassifiziert D. Rösner FP 2010 . . . 21 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: Zählen trivialer Fälle Eigenschaften können die Form haben <condition> ‘trivial‘ <property> Beispiel: prop_Insert x xs = ordered xs ==> null xs ‘trivial‘ ordered (insert x xs) where types = x::Int Testfälle, für die Bedingung zutrifft, werden als trivial klassifiziert der Anteil dieser Fälle wird im Gesamtergebnis angegeben D. Rösner FP 2010 . . . 21 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck Eigenschaften können die Form haben classify <condition> <string>$ <property> Beispiel: prop_Insert x xs = ordered xs ==> classify (ordered (x:xs)) "at-head"$ classify (ordered (xs++[x])) "at-tail"$ ordered (insert x xs) where types = x::Int Verteilung der Testfälle (die mehreren Kategorien angehören können) wird berichtet D. Rösner FP 2010 . . . 22 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck Eigenschaften können die Form haben collect <expression>$ <property> Beispiel: prop_Insert x xs = ordered xs ==> collect (length xs)$ ordered (insert x xs) where types = x::Int die Verteilung der Werte des Arguments von collect wird berichtet D. Rösner FP 2010 . . . 23 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: Implementation Kombinatoren, die Generatoren produzieren: elements . . . erzeuge zu einem aus einer Liste zufällig ausgewählten Element einen Generator elements :: [a] -> Gen a elements xs = (xs !!) ‘fmap‘ choose (0, length xs - 1) D. Rösner FP 2010 . . . 24 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: Implementation Kombinatoren, die Generatoren produzieren: elements . . . erzeuge zu einem aus einer Liste zufällig ausgewählten Element einen Generator elements :: [a] -> Gen a elements xs = (xs !!) ‘fmap‘ choose (0, length xs - 1) Beispiele: QuickCheck> [generate 5 (mkStdGen i) (choose (’a’,’f’))|i<-[0..30]] "edccbaffedccbaffedccbaffedccbaf" QuickCheck> [generate 5 (mkStdGen i) (elements [’a’..’z’])|i<-[0..30]] "bktdcluedmvfenwgfoxhgpyihqzjira" D. Rösner FP 2010 . . . 24 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: Implementation Kombinatoren, die Generatoren produzieren: vector . . . produziere einen Generator für Listen mit n zufälligen Elementen vector :: Arbitrary a => Int -> Gen [a] vector n = sequence [ arbitrary | i <- [1..n] ] D. Rösner FP 2010 . . . 25 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: Implementation Kombinatoren, die Generatoren produzieren: vector . . . produziere einen Generator für Listen mit n zufälligen Elementen vector :: Arbitrary a => Int -> Gen [a] vector n = sequence [ arbitrary | i <- [1..n] ] Beispiele: QuickCheck> generate 10 (mkStdGen 3) ( vector 10)::[[Int]] [[-2,5,5,1,-3],[-1,-3],[-6,-6],[-2,-6,0,-6,-1],[4,1,-4,-5], [2,-3,-3],[-3],[],[-2,5,3,2,5,2],[]] QuickCheck> generate 10 (mkStdGen 9) ( vector 12)::[Float] [-4.75,1.333333,-1.0,-5.333333,3.2,-3.2,4.0,-5.0,3.333333, 3.0,0.4,0.0] D. Rösner FP 2010 . . . 25 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: Implementation die Definition von vector verwendet die allgemeine monadische Funktion sequence, die aus einer Liste von Monadeninstanzen eine Monadeninstanz für eine Liste produziert D. Rösner FP 2010 . . . 26 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: Implementation die Definition von vector verwendet die allgemeine monadische Funktion sequence, die aus einer Liste von Monadeninstanzen eine Monadeninstanz für eine Liste produziert im Prelude.hs: sequence :: Monad m => [m a] -> m [a] sequence [] = return [] sequence (c:cs) = do x <- c xs <- sequence cs return (x:xs) D. Rösner FP 2010 . . . 26 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: Implementation generate . . . Funktion, um Testgeneratoren zur Ausführung zu bringen generate :: Int -> StdGen -> Gen a -> a generate n rnd (Gen m) = m size rnd’ where (size, rnd’) = randomR (0, n) rnd Erläuterung: mit Hilfe des Zufallsgenerators rnd wird im Bereich von 0 bis n ein Wert für size bestimmt der Testdatengenerator wird dann mit size und der Fortschreibung rnd’ von rnd angewendet D. Rösner FP 2010 . . . 27 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: Implementation einige Anwendungen von generate: QuickCheck> (generate 20 (mkStdGen 2) (variant 5 arbitrary))::[Float] [3.4,-3.0,1.166667,-5.4,8.3,-3.0,1.0,-9.2,7.222222] QuickCheck> (generate 20 (mkStdGen 2) (variant 6 arbitrary))::[Float] [] QuickCheck> (generate 20 (mkStdGen 2) (variant 7 arbitrary))::[Float] [-4.0,-3.916667,11.2,-1.166667,4.0,11.8,4.333333,-7.625] QuickCheck> generate 10 (mkStdGen 3) ( vector 10)::[Float] [-4.666667,-1.166667,-3.5,4.0,6.666667,0.2857143,-5.6,2.0,1.333333,-2. D. Rösner FP 2010 . . . 28 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: Implementation variant . . . Kombinator, um zu Generator gezielt Varianten erzeugen zu können D. Rösner FP 2010 . . . 29 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: Implementation variant . . . Kombinator, um zu Generator gezielt Varianten erzeugen zu können variant :: Int -> Gen a -> Gen a variant v (Gen m) = Gen (\n r -> m n (rands r !! (v+1))) where rands r0 = r1 : rands r2 where (r1, r2) = split r0 D. Rösner FP 2010 . . . 29 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: Implementation variant . . . Kombinator, um zu Generator gezielt Varianten erzeugen zu können variant :: Int -> Gen a -> Gen a variant v (Gen m) = Gen (\n r -> m n (rands r !! (v+1))) where rands r0 = r1 : rands r2 where (r1, r2) = split r0 durch wiederholtes Anwenden von split wird aus dem übergebenen Zufallsgenerator eine Liste von Zufallsgeneratoren erzeugt, aus der dann das (v+1)-te Element entnommen und dann im Testgenerator verwendet wird D. Rösner FP 2010 . . . 29 Quickcheck Einführung Generatoren Testen Weitere Aspekte Gliederung 1 Quickcheck Einführung Generatoren Testen Weitere Aspekte D. Rösner FP 2010 . . . 30 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: weitere Aspekte der Implementation Konfigurationen als Daten data Config { maxTest , maxFail , size , every } = Config :: Int :: Int :: Int -> Int :: Int -> [String] -> String D. Rösner FP 2010 . . . 31 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: Konfigurationen als Daten Beispiel: quick :: Config quick = Config { maxTest = 100 , maxFail = 1000 , size = (+ 3) . (‘div‘ 2) , every = \n args -> let s = show n in s ++ [ ’\b’ | _ <- s ] } D. Rösner FP 2010 . . . 32 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: Konfigurationen als Daten Spezialisierung verbose :: Config verbose = quick { every = \n args -> show n ++ ":\n" ++ unlines args } D. Rösner FP 2010 . . . 33 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: Konfigurationen als Daten Spezialisierung verbose :: Config verbose = quick { every = \n args -> show n ++ ":\n" ++ unlines args } die vordefinierten Toplevel-Funktionen test, quickCheck, verboseCheck :: Testable a => a -> IO () test = check quick quickCheck = check quick verboseCheck = check verbose D. Rösner FP 2010 . . . 33 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: die Funktion check check :: Testable a => Config -> a -> IO () check config a = do rnd <- newStdGen tests config (evaluate a) rnd 0 0 [] D. Rösner FP 2010 . . . 34 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: die Funktion check check :: Testable a => Config -> a -> IO () check config a = do rnd <- newStdGen tests config (evaluate a) rnd 0 0 [] aus Random.hs: newStdGen newStdGen :: IO StdGen = do rng <- getStdGen let (a,b) = split rng setStdGen a return b D. Rösner FP 2010 . . . 34 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: die Funktion tests tests :: Config -> Gen Result -> StdGen -> Int -> Int -> [[String]] -> IO () tests config gen rnd0 ntest nfail stamps | ntest == maxTest config = do done "OK, passed" ntest stamps | nfail == maxFail config = do done "Arguments exhausted after" ntest stamps | otherwise = do putStr (every config ntest (arguments result)) case ok result of Nothing -> tests config gen rnd1 ntest (nfail+1) stamps Just True -> tests config gen rnd1 (ntest+1) nfail (stamp result:stamps) Just False -> putStr ( "Falsifiable, after " ++ show ntest ++ " tests:\n" ++ unlines (arguments result) ) where result = generate (size config ntest) rnd2 gen (rnd1,rnd2) = split rnd0 D. Rösner FP 2010 . . . 35 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: der Datentyp Result Definition: data Result = Result { ok :: Maybe Bool, stamp :: [String], arguments :: [String] } D. Rösner FP 2010 . . . 36 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: der Datentyp Result Definition: data Result = Result { ok :: Maybe Bool, stamp :: [String], arguments :: [String] } Beispiel: nothing :: Result nothing = Result{ ok = Nothing, stamp = [], arguments = [] } D. Rösner FP 2010 . . . 36 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: Repräsentation testbarer Prädikate Typ Property newtype Property = Prop (Gen Result) D. Rösner FP 2010 . . . 37 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: Repräsentation testbarer Prädikate Typ Property newtype Property = Prop (Gen Result) Klasse Testable class Testable a where property :: a -> Property D. Rösner FP 2010 . . . 37 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck: Repräsentation testbarer Prädikate zugehörige Funktionen: result :: Result -> Property result res = Prop (return res) evaluate :: Testable a => a -> Gen Result evaluate a = gen where Prop gen = property a D. Rösner FP 2010 . . . 38 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck Elemente der Sprache für testbare Spezifikationen forAll forAll :: (Show a, Testable b) => Gen a -> (a -> b) -> Property forAll gen body = Prop $ do a <- gen res <- evaluate (body a) return (argument a res) where argument a res = res{ arguments = show a : arguments res } D. Rösner FP 2010 . . . 39 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck Elemente der Sprache für testbare Spezifikationen (==>) (==>) :: Testable a => Bool -> a -> Property True ==> a = property a False ==> a = property () D. Rösner FP 2010 . . . 40 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck Elemente der Sprache für testbare Spezifikationen (==>) (==>) :: Testable a => Bool -> a -> Property True ==> a = property a False ==> a = property () label label :: Testable a => String -> a -> Property label s a = Prop (add ‘fmap‘ evaluate a) where add res = res{ stamp = s : stamp res } D. Rösner FP 2010 . . . 40 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck Elemente der Sprache für testbare Spezifikationen classify classify :: Testable a => Bool -> String -> a -> Property classify True name = label name classify False _ = property D. Rösner FP 2010 . . . 41 Quickcheck Einführung Generatoren Testen Weitere Aspekte QuickCheck Elemente der Sprache für testbare Spezifikationen classify classify :: Testable a => Bool -> String -> a -> Property classify True name = label name classify False _ = property trivial trivial :: Testable a => Bool -> a -> Property trivial = (‘classify‘ "trivial") D. Rösner FP 2010 . . . 41 Quickcheck Einführung Generatoren Testen Weitere Aspekte Literatur: I Paul Hudak. The Haskell School of Expression – Learning Functional Programming through Multimedia. Cambridge University Press, Cambridge, UK, 2000. ISBN 0-521-64338-4. Simon Thompson. Haskell - The Craft of Functional Programming. Addison Wesley Longman Ltd., Essex, 1999. 2nd edition, ISBN 0-201-34275-8; Accompanying Web site: http://www.cs.ukc.ac.uk/people/staff/sjt/craft2e. D. Rösner FP 2010 . . . 42