Safe Haskell | Safe |
---|---|
Language | Haskell2010 |
GenValidity
exists to make tests involving Validity
types easier and speed
up the generation of data for them.
Let's use the example from Data.Validity
again: A datatype that represents
primes.
To implement tests for this datatype, we would have to be able to generate
both primes and non-primes. We could do this with
(Prime $ arbitrary)
but this is tedious and inefficient.suchThat
isValid
The GenValidity
type class allows you to specify how to (efficiently)
generate data of the given type to allow for easier and quicker testing.
Just implementing genUnchecked
already gives you access to genValid
and
genInvalid
but writing custom implementations of these functions may speed
up the generation of data.
For example, to generate primes, we don't have to consider even numbers other than 2. A more efficient implementation could then look as follows:
instance GenValidity Prime where genUnchecked = Prime <$> arbitrary genValid = Prime <$> (oneof [ pure 2 , (\y -> 2 * y + 1) <$> (arbitrary `suchThat` (> 0) `suchThat` isPrime) ])
Typical examples of tests involving validity could look as follows:
it "succeeds when given valid input" $ do forAll genValid $ \input -> myFunction input `shouldSatisfy` isRight
it "produces valid output when it succeeds" $ do forAll genUnchecked $ \input -> case myFunction input of Nothing -> return () -- Can happen Just output -> output `shouldSatisfy` isValid
Documentation
module Data.Validity
class Validity a => GenValidity a where Source #
A class of types for which Validity
-related values can be generated.
If you also write Arbitrary
instances for GenValidity
types, it may be
best to simply write arbitrary = genValid
.
genUnchecked :: Gen a Source #
Generate a truly arbitrary datum, this should cover all possible values in the type
Generate a valid datum, this should cover all possible valid values in the type
The default implementation is as follows:
genValid = genUnchecked `suchThat` isValid
To speed up testing, it may be a good idea to implement this yourself. If you do, make sure that it is possible to generate all possible valid data, otherwise your testing may not cover all cases.
genInvalid :: Gen a Source #
Generate an invalid datum, this should cover all possible invalid values
genInvalid = genUnchecked `suchThat` (not . isValid)
To speed up testing, it may be a good idea to implement this yourself. If you do, make sure that it is possible to generate all possible invalid data, otherwise your testing may not cover all cases.
GenValidity a => GenValidity [a] Source # | If we can generate values of a certain type, we can also generate lists of
them.
This instance ensures that |
GenValidity a => GenValidity (Maybe a) Source # | |
(GenValidity a, GenValidity b) => GenValidity (a, b) Source # | |
(GenValidity a, GenValidity b, GenValidity c) => GenValidity (a, b, c) Source # | |