LeanCheck
LeanCheck is a simple enumerative property-based testing library. Properties
are defined as Haskell functions returning a boolean value which should be
True
for all possible choices of argument values. LeanCheck applies
enumerated argument values to these properties in search for a counterexample.
Properties can be viewed as parameterized unit tests.
LeanCheck works by producing tiers of test values: a possibly infinite list
of finite sublists of same-and-increasingly-sized values. This enumeration is
similar to Feat’s. However, the ranking and ordering of values are defined
differently. The interface is also different.
Throughout this README lines that begin with the symbol >
indicate a line
entered into an interactive interpreter (ghci
). The result of evaluating the
expression is then printed on the following line.
Installing
To install the latest LeanCheck version from Hackage, just run:
$ cabal update
$ cabal install leancheck
Checking if properties are True
To check if properties are True,
just use the function holds
:: Testable a => Int -> a -> Bool
.
It takes two arguments:
the number of values to test
and a property (function returning Bool),
then, it returns a boolean indicating whether the property holds.
See (ghci):
> import Test.LeanCheck
> import Data.List
> holds 100 $ \xs -> sort (sort xs) == sort (xs::[Int])
True
> holds 100 $ \xs -> [] `union` xs == (xs::[Int])
False
Finding counter examples
To find counter examples to properties,
you can use the function counterExample
:: Testable a => Int -> a -> Maybe [String]
.
It takes two arguments:
the number of values to test
and a property (function returning Bool).
Then, it returns Nothing if no results are found or Just a list of Strings
representing the offending arguments to the property.
See (ghci):
> import Test.LeanCheck
> import Data.List
> counterExample 100 $ \xs -> sort (sort xs) == sort (xs::[Int])
Nothing
> counterExample 100 $ \xs -> [] `union` xs == (xs::[Int])
Just ["[0,0]"]
> counterExample 100 $ \xs ys -> xs `union` ys == ys `union` (xs::[Int])
Just ["[]","[0,0]"]
Checking properties like in SmallCheck/QuickCheck
To “check” properties like in SmallCheck and QuickCheck
automatically printing results on standard output,
you can use the function check
:: Testable a => a -> IO ()
.
> import Test.LeanCheck
> import Data.List
> check $ \xs -> sort (sort xs) == sort (xs::[Int])
+++ OK, passed 200 tests.
> check $ \xs ys -> xs `union` ys == ys `union` (xs::[Int])
*** Failed! Falsifiable (after 4 tests):
[] [0,0]
The function check
tests for a maximum of 200 tests.
To check for a maximum of n
tests, use checkFor
n
.
To get a boolean result wrapped in IO
, use checkResult
or checkResultFor
.
There is no “quiet” option, just use holds
or counterExample
in that case.
Testing user-defined types
LeanCheck works on properties with Listable
argument types.
Listable
instances are declared similarly to SmallCheck:
data MyType = MyConsA
| MyConsB Int
| MyConsC Int Char
| MyConsD String
instance Listable MyType where
tiers = cons0 MyConsA
\/ cons1 MyConsB
\/ cons2 MyConsC
\/ cons1 MyConsD
For types that do not have a constraning data invariant, instances can be
automatically derived with [Template Haskell] by using deriveListable
like
so:
deriveListable ''MyType
The tiers
function return a potentially infinite list of finite sub-lists
(tiers). Each successive tier has values of increasing size.
tiers :: Listable a => [[a]]
For convenience, the function list
returns a potentially infinite list
of values of the bound type:
list :: Listable a => [a]
So, for example:
> take 5 (list :: [(Int,Int)])
[(0,0),(0,1),(1,0),(0,-1),(1,1)]
The list
function can be used to debug your custom instances.
Listable
class instances are more customizable than what is described here:
check source comments or haddock documentation for details.
Further reading
For a detailed documentation of each function, see
LeanCheck’s Haddock documentation.
For an introduction to property-based testing
and a step-by-step guide to LeanCheck, see the
tutorial on property-based testing with LeanCheck
(doc/tutorial.md
in the source repository).