Szukaj…


Deklarowanie właściwości

Najprościej mówiąc, właściwość jest funkcją, która zwraca Bool .

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

Właściwość deklaruje niezmiennik wysokiego poziomu programu. Tester QuickCheck oceni funkcję za pomocą 100 losowych danych wejściowych i sprawdzi, czy wynik jest zawsze True .

Zgodnie z konwencją funkcje będące właściwościami mają nazwy rozpoczynające się od prop_ .

Sprawdzanie pojedynczej właściwości

Funkcja quickCheck sprawdzania testuje właściwość na 100 losowych wejściach.

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

Jeśli właściwość nie powiedzie się dla niektórych danych wejściowych, quickCheck wydrukuje kontrprzykład.

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

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

Sprawdzanie wszystkich właściwości w pliku

quickCheckAll to pomocnik szablonów Haskell, który znajduje wszystkie definicje w bieżącym pliku, którego nazwa zaczyna się od prop_ i testuje je.

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

Zauważ, że wymagany jest wiersz return [] . To sprawia, że definicje tekstowo powyżej tej linii są widoczne dla Template Haskell.

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

Losowe generowanie danych dla niestandardowych typów

Klasa Arbitrary jest przeznaczona dla typów, które mogą być generowane losowo przez QuickCheck.

Minimalna implementacja Arbitrary to arbitrary metoda, która działa w monadzie Gen celu wygenerowania losowej wartości.

Oto przykład Arbitrary dla następującego typu danych niepustych list.

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
        ]

Korzystanie z implikacji (==>) w celu sprawdzenia właściwości z warunkami wstępnymi

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

Jeśli chcesz sprawdzić, czy właściwość jest przechowywana, biorąc pod uwagę, że warunek ten jest spełniony, możesz użyć operatora ==> . Zauważ, że jeśli bardzo mało prawdopodobne jest, aby arbitralne dane wejściowe pasowały do warunku wstępnego, QuickCheck może zrezygnować wcześnie.

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

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

Ograniczanie wielkości danych testowych

Testowanie funkcji o niskiej złożoności asymptotycznej może być trudne przy użyciu szybkiej kontroli, ponieważ losowe dane wejściowe zwykle nie są ograniczone rozmiarem. Dodając górną granicę wielkości wejścia, możemy nadal testować te drogie funkcje.

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

Używając quickCheckWith ze zmodyfikowaną wersją stdArgs , możemy ograniczyć rozmiar danych wejściowych do maksymalnie 10. W tym przypadku, ponieważ generujemy listy, oznacza to, że generujemy listy do rozmiaru 10. Nasza funkcja permutacji nie zbyt długo pracujemy nad tymi krótkimi listami, ale nadal możemy być dość pewni, że nasza definicja jest poprawna.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow