Buscar..


Declarar una propiedad

En su forma más simple, una propiedad es una función que devuelve un Bool .

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

Una propiedad declara un invariante de alto nivel de un programa. El corredor de pruebas QuickCheck evaluará la función con 100 entradas aleatorias y verificará que el resultado sea siempre True .

Por convención, las funciones que son propiedades tienen nombres que comienzan con prop_ .

Comprobando una sola propiedad

La función quickCheck prueba una propiedad en 100 entradas aleatorias.

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

Si una propiedad falla para alguna entrada, quickCheck imprime un contraejemplo.

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

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

Comprobando todas las propiedades en un archivo

quickCheckAll es un ayudante de Haskell de plantillas que encuentra todas las definiciones en el archivo actual cuyo nombre comienza con prop_ y las prueba.

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

Tenga en cuenta que la línea de return [] es obligatoria. Hace que las definiciones textuales sobre esa línea sean visibles para la Plantilla Haskell.

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

Generando datos al azar para tipos personalizados

La clase Arbitrary es para tipos que QuickCheck puede generar aleatoriamente.

La implementación mínima de Arbitrary es el método arbitrary , que se ejecuta en la mónada Gen para producir un valor aleatorio.

Aquí hay una instancia de Arbitrary para el siguiente tipo de datos de listas no vacías.

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
        ]

Usando la implicación (==>) para verificar las propiedades con condiciones previas

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

Si desea verificar que una propiedad se cumple dado que se cumple una condición previa, puede usar el operador ==> . Tenga en cuenta que si es muy poco probable que las entradas arbitrarias coincidan con la condición previa, QuickCheck puede darse por vencido antes.

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

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

Limitar el tamaño de los datos de prueba

Puede ser difícil probar funciones con poca complejidad asintótica mediante el uso de la comprobación rápida, ya que las entradas aleatorias no suelen tener límites de tamaño. Al agregar un límite superior en el tamaño de la entrada, aún podemos probar estas funciones costosas.

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

Al usar quickCheckWith con una versión modificada de stdArgs , podemos limitar el tamaño de las entradas para que sean como máximo 10. En este caso, ya que estamos generando listas, esto significa que generamos listas de hasta tamaño 10. Nuestra función de permutaciones no tomar demasiado tiempo para estas listas cortas, pero todavía podemos estar razonablemente seguros de que nuestra definición es correcta.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow