- Rather than using conditionals (
if,unless,when) when preconditions aren't met, use==>ordiscardfrom Hedgehog. - Ensure that generators have high coverage, consider writing tests that guarantee that the generators can generate all relevant shapes of data within some relatively small number of samples.
- Don't provide explanatory comments for very simple algebraic properties such
as reflexivity of
==.
Ensure that every nontrivial typeclass instance has tests for each of the following properties:
Eqx == xx == y ==> y == xx == y && y == z ==> x == z
Ordx <= y && y <= x ==> x == yx <= y && y <= z ==> x <= zx <= y || y <= xcompare x y == EQ ==> x == y
Eq1liftEq (==) x y == (x == y)
Ord1liftCompare compare x y == compare x y
Hashablex == y ==> hash x == hash y
Functorfmap id == idfmap (f . g) == fmap f . fmap g
Applicativepure id <*> v == vpure (.) <*> u <*> v <*> w == u <*> (v <*> w)pure f <*> pure x == pure (f x)u <*> pure y == pure ($ y) <*> u
Monadreturn x >>= f == f xm >>= return == m(m >>= f) >>= g == m >>= (\x -> f x >>= g)
Traversabletraverse Identity == Identitytraverse (Compose . fmap g . f) == Compose . fmap (traverse g) . traverse f
Bifunctorbimap id id == idbimap (f . g) (h . i) == bimap f h . bimap g i
Bitraversablebitraverse (Identity . f) (Identity . g) == Identity . bimap f gbitraverse (Compose . fmap g . f) (Compose . fmap i . h) == Compose . fmap (bitraverse g i) . bitraverse f h
Semigroup(x <> y) <> z == x <> (y <> z)
Monoidx <> mempty == xmempty <> x == x(x <> y) <> z == x <> (y <> z)
Alternativeempty <|> x == xx <|> empty == x(x <|> y) <|> z == x <|> (y <|> z)
MonadPlusmzero >>= f == mzerom >> mzero == mzero
Property quick reference
| Property | Formula | When to Use |
|---|---|---|
| Roundtrip | decode(encode(x)) == x |
Serialization, conversion pairs |
| Idempotence | f(f(x)) == f(x) |
Normalization, formatting, sorting |
| Invariant | Property holds before/after | Any transformation |
| Commutativity | f(a, b) == f(b, a) |
Binary/set operations |
| Associativity | f(f(a,b), c) == f(a, f(b,c)) |
Combining operations |
| Identity | f(x, identity) == x |
Operations with neutral element |
| Inverse | f(g(x)) == x |
encrypt/decrypt, compress/decompress |
| Oracle | new_impl(x) == reference(x) |
Optimization, refactoring |
| Easy to Verify | is_sorted(sort(x)) |
Complex algorithms |
| No Exception | No crash on valid input | Baseline property |
Strength hierarchy (weakest to strongest): No Exception → Type Preservation → Invariant → Idempotence → Roundtrip
Converted and distributed by TomeVault — claim your Tome and manage your conversions.