Reputation: 62848
I'm having trouble with a programming problem here. Half the trouble is that the problem itself is quite tricky to think about, and the other half is that I can't remember how to find my way around QuickCheck.
I know that if you write a function that takes several arguments that have an Arbitrary
instance, QuickCheck will let you use that method as a test. What I can't figure out is how to generate new test arguments inside that method. I want to write something like
prop13 :: Foo -> Bar -> Bool
prop13 foo bar =
if foobar foo bar
then fn1 foo
else newInput $ \ baz -> fn2 foo bar baz
but I can't figure out how the hell to do that.
Actually, no, what I really want to write is
prop13 :: Foo -> Bar -> Property
prop13 foo bar =
if foobar foo bar
then label "foobar=YES" $ fn1 foo
else label "foobar=NO" $ newInput $ \ baz -> fn2 foo bar baz
just so I can check it isn't taking one branch 100% of the time or something ridiculous like that.
Actually, what would be great is if I could demand that baz
has some particular property. I vaguely remember QuickCheck having a function somewhere to throw away inputs not satisfying a given condition. (The only problem being that it might take an unreasonably number of attempts to satisfy the condition...)
Is there a way to do this? I'm staring at the Haddock page, but I can't figure out how to get what I want...
Upvotes: 3
Views: 145
Reputation: 62848
I found the answer in another answer. Apparently it's forAll
:
else forAll arbitrary $ \ baz -> fn2 foo bar baz
I just couldn't remember how to do it...
(This also has the nice feature of allowing me to specify a specific random data generator.)
Upvotes: 4
Reputation: 1918
A property may take the form
classify <condition> <string>$ <property>
For example,
prop_Insert x xs = ordered xs ==> classify (ordered (x:xs)) "at-head" $ classify (ordered (xs ++ [x])) "at-tail" $ ordered (insert x xs) where types = x :: Int
Test cases satisfying the condition are assigned the classification given, and the distribution of classifications is reported after testing. In this case the result is
Main> quickCheck prop_Insert OK, passed 100 tests. 58% at-head, at-tail. 22% at-tail. 4% at-head.
Note that a test case may fall into more than one classification.
(from QuickCheck manual)
For demanding the particular property of the input data, you may add somePredicate data ==>
before the test body, as it is shown in the snippet above. Another example:
prop_max xs = (not . null xs) ==> head (sort xs) == maximum xs
You're right, this combinator throws away inappropriate cases. If that's undesired, you can make a newtype
wrapper over the input type and redefine the Arbitrary
instance for it (see examples of Positive
, NonEmpty
and so on here)
Upvotes: 4