hedgehog Hackage Travis

Hedgehog will eat all your bugs.

Hedgehog is a modern property-based testing system, in the spirit of QuickCheck. Hedgehog uses integrated shrinking, so shrinks obey the invariants of generated values by construction.

Features

  • Integrated shrinking, shrinks obey invariants by construction.
  • Abstract state machine testing.
  • Generators allow monadic effects.
  • Range combinators for full control over the scope of generated numbers and collections.
  • Equality and roundtrip assertions show a diff instead of the two inequal values.
  • Template Haskell test runner which executes properties concurrently.

Example

The main module, Hedgehog, includes almost everything you need to get started writing property tests with Hedgehog.

It is designed to be used alongside Hedgehog.Gen and Hedgehog.Range which should be imported qualified. You also need to enable Template Haskell so the Hedgehog test runner can find your properties.

{-# LANGUAGE TemplateHaskell #-}

import           Hedgehog
import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range

Once you have your imports set up, you can write a simple property:

prop_reverse :: Property
prop_reverse =
  property $ do
    xs <- forAll $ Gen.list (Range.linear 0 100) Gen.alpha
    reverse (reverse xs) === xs

And add the Template Haskell splice which will discover your properties:

tests :: IO Bool
tests =
  checkParallel $$(discover)

If you prefer to avoid macros, you can specify the group of properties to run manually instead:

{-# LANGUAGE OverloadedStrings #-}

tests :: IO Bool
tests =
  checkParallel $ Group "Test.Example" [
      ("prop_reverse", prop_reverse)
    ]

You can then load the module in GHCi, and run it:

λ tests
━━━ Test.Example ━━━
  ✓ prop_reverse passed 100 tests.

Changes

Version 0.6.1 (2018-09-22)

  • Set stdout/stderr encoding to UTF-8 on Windows ([#218][218], @moodmosaic)

Version 0.6 (2018-05-14)

Version 0.5.3 (2018-03-12)

Version 0.5.2 (2018-02-05)

Version 0.5.1 (2017-12-06)

Version 0.5 (2017-07-16)

  • Parallel state machine testing, allows detection of commands which are not-atomic (#98, @jystic)
  • Easier to use variables for state machine testing (#94, @jystic)
  • MonadGen class allows the use of transformers like ReaderT and StateT on the outside of generators (#99, @jystic)
  • Better error messages for tests which throw exceptions (#95, @jystic)
  • Separated test input generation and assertions in to PropertyT and TestT respectively, this allows TestT to have a MonadBaseControl instance (#96, @jystic)
  • This document grew links to the pull requests which introduced various changes (#93, @moodmosaic)

Version 0.4.1 (2017-06-28)

  • Fixed runtime type error that could occur when shrinking state machine commands (#91, @jystic)

Version 0.4 (2017-06-28)

Version 0.3 (2017-06-11)

  • Exponential range combinators (#43, @chris-martin)
  • Roundtrip example, check out the blog post (#85, @thumphries)
  • tripping now displays intermediate value (#85, @jystic)
  • distribute function for pulling a transformer out to the top level (#83, @jystic)
  • withExceptT function for executing tests with an inner ExceptT (e.g. Test (ExceptT x m) a) (#83, @jystic)

Version 0.2.2 (2017-05-16)

Version 0.2.1 (2017-05-09)

  • Added ascii, latin1, unicode character generators (#73, @jystic)

Version 0.2 (2017-05-06)

  • Added a quiet test runner which can be activated by setting HEDGEHOG_VERBOSITY=0 (@jystic)
  • Concurrent test runner does not display tests until they are executing (@jystic)
  • Test runner now outputs a summary of how many successful / failed tests were run (@jystic)
  • checkSequential and checkParallel now allow for tests to be run without Template Haskell (@jystic)
  • Auto-discovery of properties is now available via discover instead of being baked in (@jystic)
  • annotate allows source code to be annotated inline with extra information (@jystic)
  • forAllWith can be used to generate values without a Show instance (@jystic)
  • Removed uses of Typeable to allow for generating types which cannot implement it (@jystic)