Quickcheck, defining Arbitrary instances using a function whose result depends on its arguments

755 views Asked by At

I have a function arbExample to generate a random Example data type which depends on a numbers of functions.

I am trying to do some property testing by doing quickCheck prop_example, the problem is I don't know how to define an Arbitrary instance for Example which uses arbExample.

I like to be able run quickCheck prop_example while specifying the Gens data structure which arbExample uses.

data Example = Example
    { myInt  :: Int 
    , myList :: [String]
    } deriving (Show)

data Gens =  Gens
    { gen1 :: Gen Int
    , gen2 :: Gen String }

arbExample :: Gens -> Gen Example
arbExample gens = do 
    i  <- gen1 gens 
    xs <- vectorOf i (gen2 gens)
    return Example{myInt=i, myList=xs}

prop_example :: Example -> Property
prop_example example =  do
    let len = length (myList example) 
    monadicIO $ do 
        -- result of running some program
        successful <- run $ (\e -> return False) example  
        case successful of
            True  -> return ()
            False -> fail "failure "

instance Arbitrary Example where
    arbitrary =  arbExample _ {- ??? -}
1

There are 1 answers

1
ErikR On

Use the forAll combinator which has the signature:

forAll :: (Show a, Testable prop) => Gen a -> (a -> prop) -> Property

A quick example:

import Test.QuickCheck

genA :: Gen Int
genA = choose (-100,100)

genB :: Gen Int
genB = choose (1,100)

prop_example :: Int -> Bool
prop_example n = n > 0

testA = quickCheck $ forAll genA prop_example
testB = quickCheck $ forAll genB prop_example

testA will fail but testB will succeed.