# \[RFC\] hspec-quickcheck-classes: testing typeclass laws from Hspec

**URL:** <https://discourse.haskell.org/t/rfc-hspec-quickcheck-classes-testing-typeclass-laws-from-hspec/13919>\
**Category:** Show and Tell\
**Created:** [April 11, 2026, 8:44am UTC](https://discourse.haskell.org/t/rfc-hspec-quickcheck-classes-testing-typeclass-laws-from-hspec/13919 "2026-04-11T08:44:32Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![jonathanknowles](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/jonathanknowles/32/1653_2.png) [@jonathanknowles](https://discourse.haskell.org/u/jonathanknowles)\
**Post date:** [April 11, 2026, 8:44am UTC](https://discourse.haskell.org/t/rfc-hspec-quickcheck-classes-testing-typeclass-laws-from-hspec/13919/1 "2026-04-11T08:44:32Z")

</div>

I’ve created a small library called [`hspec-quickcheck-classes`](https://github.com/jonathanknowles/hspec-quickcheck-classes), for testing typeclass laws within [`Hspec`](https://hackage.haskell.org/package/hspec) specifications.

It’s a tiny library (with just **one** function), but I’d be very grateful for any feedback before I release it on Hackage.

## What problem does it solve?

This library integrates [`Hspec`](https://hackage.haskell.org/package/hspec) with [`quickcheck-classes`](https://hackage.haskell.org/package/quickcheck-classes). For those not familiar:

- [`Hspec`](https://hackage.haskell.org/package/hspec) is a very popular Haskell testing framework that provides a readable DSL for structuring tests.

- [`quickcheck-classes`](https://hackage.haskell.org/package/quickcheck-classes) is a library that provides QuickCheck property tests for the laws of typeclasses such as `Eq`, `Ord`, `Functor`, `Applicative`, `Monad`, and many others. It defines a [`Laws`](https://hackage.haskell.org/package/quickcheck-classes-0.6.5.0/docs/Test-QuickCheck-Classes.html#t:Laws) data type, which bundles together a list of named properties for a single typeclass.

Using `quickcheck-classes` within an `Hspec` specification requires a small but repetitive amount of **boilerplate**.

This library handles this boilerplate for you, constructing a [`Spec`](https://hackage-content.haskell.org/package/hspec-2.11.17/docs/Test-Hspec.html#t:Spec) from a given type and a set of [`Laws`](https://hackage.haskell.org/package/quickcheck-classes-0.6.5.0/docs/Test-QuickCheck-Classes.html#t:Laws). The generated `Spec` consists of a tree with an outer node for the type, an inner node for each typeclass, and a leaf for each law being tested (where each law has a corresponding QuickCheck property):

```haskell
<type> ← outer node (type)
├── <typeclass #a> ← inner node (typeclass)
│ ├── <law #1> ← leaf (law)
│ ├── <law #2>
│ └── ...
├── <typeclass #b>
│ ├── <law #1>
│ ├── <law #2>
│ └── ...
└── <typeclass #c>
    ├── <law #1>
    ├── <law #2>
    └── ...
...

```

## The API

The library exposes just a single function:

```haskell
testLaws
  :: forall a. (Typeable a, HasCallStack) 
  => [Proxy a -> Laws]
  -> Spec

```

Usage looks like this:

```haskell
import Test.Hspec
  ( hspec )
import Test.Hspec.QuickCheck.Classes
  ( testLaws )
import Test.QuickCheck
  ( Arbitrary (..) )
import Test.QuickCheck.Classes
  ( eqLaws, ordLaws, showLaws )

-- Import the data type you'd like to test:
import Data.Foo
  ( Foo (..) )

-- Define (or import) an 'Arbitrary' instance for your data type:
instance Arbitrary Foo where
  arbitrary = ...
  shrink = ...

main :: IO ()
main = hspec $ do

  -- Test that your data type obeys the laws of 'Eq', 'Ord', and 'Show':
  testLaws @Foo
    [ eqLaws
    , ordLaws
    , showLaws
    ]

```

This produces output along the lines of:

```haskell
Testing laws for Foo
  Eq
    Transitive [✔]
      +++ OK, passed 100 tests.
    Symmetric [✔]
      +++ OK, passed 100 tests.
    Reflexive [✔]
      +++ OK, passed 100 tests.
  Ord
    Antisymmetry [✔]
      +++ OK, passed 100 tests.
    Transitivity [✔]
      +++ OK, passed 100 tests.
    Totality [✔]
      +++ OK, passed 100 tests.
  Show
    Show [✔]
      +++ OK, passed 100 tests.
    Equivariance: showsPrec [✔]
      +++ OK, passed 100 tests.
    Equivariance: showList [✔]
      +++ OK, passed 100 tests.

```

On **failure** , the output includes a **counterexample** , and the **location** of the test that failed in the test source code.

For example, here’s a failing test taken from the [`monoidmap`](https://hackage.haskell.org/package/monoidmap) package, showing a violation of the [`LeftReductive`](https://hackage-content.haskell.org/package/quickcheck-monoid-subclasses-0.3.0.6/docs/Test-QuickCheck-Classes-Semigroup-Cancellative.html#v:leftReductiveLaws) laws (due to a deliberately-introduced bug):

```haskell
test/Data/MonoidMap/Internal/ClassSpec.hs:92:9: 
1) Data.MonoidMap, Testing laws for MonoidMap String String, LeftReductive, leftReductiveLaw_stripPrefix
   Falsified (after 20 tests and 10 shrinks):
   Property not satisfied:
     maybe b (a <>) (stripPrefix a b) == b
   Values:
     a =
       fromList []
     b =
       fromList [("A","a")]
     stripPrefix a b =
       Just (fromList [("A","a")])
     maybe b (a <>) (stripPrefix a b) =
       fromList []

```

### Kind polymorphism

To support testing of laws for higher-kinded classes like `Functor`, `Applicative`, and `Traversable`, the `testLaws` function is kind-polymorphic, with no special casing required.

For example, with `Maybe`, which has kind `Type -> Type`:

```haskell
testLaws @Maybe
  [ applicativeLaws
  , functorLaws
  , monadLaws
  , foldableLaws
  , traversableLaws
  ]

```

And `Either`, which has kind `Type -> Type -> Type`:

```haskell
testLaws @Either
  [ bifoldableLaws
  , bifunctorLaws
  , bitraversableLaws
  ]

```

## Feedback

Obviously this is a tiny library, but if anyone has any feedback they’d like to share about the API, the [documentation](https://jonathanknowles.github.io/hspec-quickcheck-classes/Test-Hspec-QuickCheck-Classes.html), or the [implementation](https://github.com/jonathanknowles/hspec-quickcheck-classes/blob/main/components/lib/Test/Hspec/QuickCheck/Classes.hs), I’d be very grateful to hear your thoughts before the library is published.

Many thanks for reading!

---

<div class="post-metadata">

**Author:** ![jonathanknowles](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/jonathanknowles/32/1653_2.png) [@jonathanknowles](https://discourse.haskell.org/u/jonathanknowles)\
**Post date:** [April 17, 2026, 4:23am UTC](https://discourse.haskell.org/t/rfc-hspec-quickcheck-classes-testing-typeclass-laws-from-hspec/13919/2 "2026-04-17T04:23:07Z")

</div>

Just a quick update: `hspec-quickcheck-classes` is now available on Hackage:

- [hspec-quickcheck-classes: Integration between Hspec and quickcheck-classes](https://hackage.haskell.org/package/hspec-quickcheck-classes)

Many thanks to those who read through the RFC!
