An algebraic law is a characteristic that an implementation should satisfy for every relevant input. In QuickCheck, such a law is written as a property: often a predicate returning Bool, but also a value of QuickCheck’s Property type or a function returning either. Rather than list expected outputs, run the property against generated inputs to look for counterexamples. section 9.1.1 section 9.3.1
Start with a relationship that should remain true regardless of particular data. A sorting function should produce a sorted list; applying rot13 twice should return the original string; an alphabet rotation should return a character contained in its alphabet. Equality checks against fixed expected values are a simple form of the same idea, but laws can combine predicates and rules into broader checks. section 9.1.1 section 9.3.1
Listing 9.1 Predicates on the sortedness of lists
sorted :: Ord a => [a] -> Bool sorted [] = True #1 sorted [_] = True #1 sorted (x : y : xs) = x <= y && sorted (y : xs) #2 sorts :: Ord a => ([a] -> [a]) -> [a] -> Bool sorts f input = sorted $ f input #3
This pair of predicates separates the invariant, sorted, from the property that applies it to any list-transforming function. The Ord constraint supplies the comparison needed to check adjacent elements. section 9.1.1
Check a symmetry law
A symmetry property can be written as prop_rot13Symm s = s == rot13 (rot13 s). Running quickCheck prop_rot13Symm tests generated strings. An incorrect refactoring fails with the counterexample "a"; QuickCheck shrinks failing inputs toward a smaller counterexample when it can. section 9.3.1
Refine a property when generated tests are misleading or insufficient:
- Give the property an explicit type, such as [Int] -> Bool, to avoid type defaulting to unit values that make sortedness trivial. section 9.5.1
- Use verbose to inspect generated cases, and collect or label to report how input categories are distributed. section 9.5.1
- Use a precondition with ==> when only inputs meeting a rule matter, while watching discarded tests. section 9.5.1
- Use cover to require and report a desired proportion of a category, such as non-trivial lists. section 9.5.1
Properties can become a runnable test suite. Name them with the prop_ prefix, use Template Haskell’s quickCheckAll to find and run them in a module, combine suite results in Main, and return a success or failure exit code so stack test reports the result. Modifiers can adjust a property’s run, for example withMaxSuccess, noShrinking, or cover. section 9.5.3 section 9.6

