Ricerca…


Dichiarare una proprietà

Nel modo più semplice, una proprietà è una funzione che restituisce un Bool .

prop_reverseDoesNotChangeLength xs = length (reverse xs) == length xs

Una proprietà dichiara un invariante di alto livello di un programma. Il test runner QuickCheck valuterà la funzione con 100 input casuali e verificherà che il risultato sia sempre True .

Per convenzione, le funzioni che hanno proprietà hanno nomi che iniziano con prop_ .

Controllo di una singola proprietà

La funzione quickCheck verifica una proprietà su 100 input casuali.

ghci> quickCheck prop_reverseDoesNotChangeLength
+++ OK, passed 100 tests.

Se una proprietà fallisce per qualche input, quickCheck stampa un controesempio.

prop_reverseIsAlwaysEmpty xs = reverse xs == []  -- plainly not true for all xs

ghci> quickCheck prop_reverseIsAlwaysEmpty
*** Failed! Falsifiable (after 2 tests):                  
[()]

Controllo di tutte le proprietà in un file

quickCheckAll è un helper Template Haskell che trova tutte le definizioni nel file corrente il cui nome inizia con prop_ e le prop_ .

{-# 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

Si noti che è richiesta la riga return [] . Rende le definizioni testuali sopra quella linea visibili a Template Haskell.

$ runhaskell QuickCheckAllExample.hs
=== prop_sortIdempotent from tree.hs:7 ===
+++ OK, passed 100 tests.

Generazione casuale di dati per tipi personalizzati

La classe Arbitrary è per tipi che possono essere generati casualmente da QuickCheck.

L'implementazione minima di Arbitrary è il metodo arbitrary , che viene eseguito nella Gen Monad per produrre un valore casuale.

Ecco un'istanza di Arbitrary per il seguente tipo di dati di liste non vuote.

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
        ]

Utilizzo dell'implicazione (==>) per controllare le proprietà con le condizioni preliminari

prop_evenNumberPlusOneIsOdd :: Integer -> Property
prop_evenNumberPlusOneIsOdd x = even x ==> odd (x + 1)

Se si desidera verificare che una proprietà sia valida dato che una precondizione è valida, è possibile utilizzare l'operatore ==> . Nota che se è molto improbabile che gli input arbitrari soddisfino la condizione preliminare, QuickCheck può rinunciare presto.

prop_overlySpecific x y = x == 0 ==> x * y == 0

ghci> quickCheck prop_overlySpecific
*** Gave up! Passed only 31 tests.

Limitazione della dimensione dei dati di test

Può essere difficile testare le funzioni con una scarsa complessità asintotica usando quickcheck in quanto gli input casuali non sono in genere legati alle dimensioni. Aggiungendo un limite superiore alla dimensione dell'input possiamo ancora testare queste costose funzioni.

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

Usando quickCheckWith con una versione modificata di stdArgs possiamo limitare la dimensione degli input al massimo 10. In questo caso, dato che stiamo generando liste, questo significa che generiamo liste fino alla dimensione 10. La nostra funzione permutazioni non impiegare troppo tempo per eseguire queste brevi liste, ma possiamo ancora essere ragionevolmente sicuri che la nostra definizione sia corretta.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow