Поиск…


Объявление собственности

В своем простейшем случае свойство является функцией, которая возвращает Bool .

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

Свойство объявляет высокоуровневый инвариант программы. Тестер QuickCheck проверит функцию со 100 случайными входами и проверит, что результат всегда True .

По соглашению функции, которые являются свойствами, имеют имена, которые начинаются с prop_ .

Проверка одного объекта

Функция quickCheck проверяет свойство на 100 случайных входах.

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

Если свойство некорректно для некоторого ввода, quickCheck распечатывает контрпример.

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

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

Проверка всех свойств в файле

quickCheckAll - это помощник шаблона Haskell, который находит все определения в текущем файле, имя которого начинается с 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

Обратите внимание, что требуется строка return [] . Он делает текстовые надписи над этой строкой видимыми для Template Haskell.

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

Произвольное генерирование данных для пользовательских типов

Класс Arbitrary предназначен для типов, которые могут быть случайно сгенерированы QuickCheck.

Минимальная реализация Arbitrary - это arbitrary метод, который выполняется в монаде Gen для получения случайного значения.

Вот пример Arbitrary для следующего типа данных непустых списков.

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
        ]

Использование импликации (==>) для проверки свойств с предварительными условиями

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

Если вы хотите проверить, что свойство выполнено, если выполнено предварительное условие, вы можете использовать оператор ==> . Обратите внимание: если очень маловероятно, чтобы произвольные входы соответствовали предварительному условию, QuickCheck может отказаться раньше.

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

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

Ограничение размера тестовых данных

Трудно проверить функции с плохой асимптотической сложностью, используя quickcheck, поскольку случайные входы обычно не ограничены размером. Добавив верхнюю границу размера ввода, мы все еще можем проверить эти дорогостоящие функции.

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

Используя quickCheckWith с модифицированной версией stdArgs мы можем ограничить размер входов не более 10. В этом случае, когда мы создаем списки, это означает, что мы генерируем списки размером до 10. Наша функция перестановок не занимать слишком много времени для выполнения этих коротких списков, но мы все же можем быть достаточно уверенными в правильности нашего определения.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow