2013-08-29 3 views
11

Używam QuickCheck przetestować następujący program:Dlaczego funkcja QuickCheck rezygnuje?

{-# LANGUAGE TemplateHaskell #-} 

import Test.QuickCheck 
import Test.QuickCheck.All 

elementAt :: (Integral b) => [a] -> b -> a 
elementAt [x] _ = x 
elementAt (x:xs) 1 = x 
elementAt (x:xs) b = elementAt xs (b - 1) 

prop_elementAt xs b = length xs > 0 && b >= 0 && b < length xs ==> elementAt xs (b + 1) == xs !! b 

main = $(quickCheckAll) 

Choć odpowiedź jest różna, ja ciągle pojawia się komunikat

*** Gave up! Passed only x tests. 

jest to coś powinienem być zaniepokojony? A może charakter wejścia testowego określa, jak długo będzie działać QuickCheck?

Odpowiedz

17

Sposób ==> prace to przede QuickCheck generuje wartości losowe dla xs i b, a następnie sprawdzić, czy orzeczenie length xs > 0 && b >= 0 && b < length xs jest spełniony tylko wtedy będzie sprawdzać dla spełnialności nieruchomości.

Ponieważ istnieje limit liczby przypadków testowych, które wygeneruje, może się zdarzyć, że wiele razy powyższy predykat nie zostanie spełniony. Tak więc kontrola quickcheck poddaje się przed wygenerowaniem wystarczającej liczby poprawnych testcases (spełniających predykat).

Zamiast tego należy zadeklarować instancję Arbitrary na nowy typ, aby generować tylko te testowe, które spełniają te predykaty.

{-# LANGUAGE TemplateHaskell #-} 

import Test.QuickCheck 
import Test.QuickCheck.All 

elementAt :: (Integral b) => [a] -> b -> a 
elementAt [x] _ = x 
elementAt (x:xs) 1 = x 
elementAt (x:xs) b = elementAt xs (b - 1) 

prop_elementAt (Foo xs b) = elementAt xs (b + 1) == xs !! b 

data Foo a b = Foo [a] b deriving (Show) 

instance (Integral b, Arbitrary a, Arbitrary b) => Arbitrary (Foo a b) where 
    arbitrary = do 
    as <- listOf1 arbitrary   -- length xs > 0 
    b <- choose (0,length as - 1)  -- b >= 0 and b < length xs 
    return (Foo as $ fromIntegral b) 

main = $(quickCheckAll) 
+0

miał ten sam problem z tym samym [99 Haskell Problemy pytaniem] (http://www.haskell.org/haskellwiki/99_questions/1_to_10) i wydaje się działać prawidłowo. Ale uruchomienie 'verboseCheck prop_elementAt' dla mnie zwraca nieskończone listy składające się tylko z elementu'() ', co oznacza, że ​​implementacja' elementAt (x: xs) _ = x' nadal przechodzi. Masz pomysł, jak wygenerować listę z rzeczywistymi elementami? – ThomasH

+1

To dlatego, że zawiera błędny typ prop_elemAt. Podaj wyraźny typ (przykład 'prop_elementAt :: Foo [Int] Int -> Bool'). – Satvik

+0

To rozwiązało, dzięki! – ThomasH