Test.QuickCheck: speed up testing of multiple properties for the same type

I am testing a random generator generating instances of my own type. For this, I have my own instance of Arbitrary :

 complexGenerator :: (RandomGen g) => g -> (MyType, g) instance Arbitrary MyType where arbitrary = liftM (fst . complexGenerator . mkStdGen) arbitrary 

This works well with Test.QuickCheck (in fact, Test.Framework ) to verify that the generated values โ€‹โ€‹contain certain properties. However, there are many properties that I want to test, and the more I add, the more time is required to check them.

Is there a way to use the same generated values โ€‹โ€‹to test each property, and not generate them again every time? Obviously, I still want to see, on failure, which property did not execute, so creating one giant property with and not optimal.

+4
source share
2 answers

Obviously, I still want to see, on failure, which property did not execute, so creating one giant property with and not optimal.

You can mark each property using printTestCase before creating a giant property with conjoin .

eg. you thought it would be a bad idea:

 prop_giant :: MyType -> Bool prop_giant x = and [prop_one x, prop_two x, prop_three x] 

it will be just as effective, but it will give you better performance:

 prop_giant :: MyType -> Property prop_giant x = conjoin [printTestCase "one" $ prop_one x, printTestCase "two" $ prop_two x, printTestCase "three" $ prop_three x] 

(Having said that, I have never used this method myself and assume that it will work; conjoin is probably flagged as experimental in the documentation for a reason.)

+3
source

In combination with the voice response that I found useful, a Reader converter with the Writer monad is used:

 type Predicate r = ReaderT r (Writer String) Bool 

A โ€œshared reading environmentโ€ is a valid input in this case. Then you can create properties like this:

 inv_even :: Predicate Int inv_even = do lift . tell $ "this is the even invariant" (==) 0 . flip mod 2 <$> ask toLabeledProp :: r -> Predicate r -> Property toLabeledProp cause r = let (effect, msg) = runWriter . (runReaderT r) $ cause in printTestCase ("inv: " ++ msg) . property $ effect 

and association:

 fromPredicates :: [Predicate r] -> r -> Property fromPredicates predicates cause = conjoin . map (toLabeledProp cause) $ predicates 

I suspect that there is another approach related to something similar to Either WriterT or here, which will be compressed to compose predicates of different types into one result. But at least this allows you to document the properties that impose different post-conventions, depending on the value of the input.

Edit: this idea spawned a library: http://github.com/jfeltz/quickcheck-property-comb

+1
source

All Articles