Skip to content

Instantly share code, notes, and snippets.

@ggazzi
Last active April 18, 2017 16:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ggazzi/78ec40fc4cdec8d15880dbedfb11e49e to your computer and use it in GitHub Desktop.
Save ggazzi/78ec40fc4cdec8d15880dbedfb11e49e to your computer and use it in GitHub Desktop.
Testing in Haskell

Testing in Haskell

Defining Tests

There are two main kinds of automated testing supported by Haskell testing libraries:

  • Unit tests, where some data is generally hardcoded. Generally, each test case will be designed to cover a class of possible inputs. They explicitly cover many cases, but if the tester forgets some corner case, it will certainly not be covered.

  • Property tests, where some data is randomly generated for the tests. This has no guarantee of covering all classes of possible inputs, but there is a large chance of capturing unforeseen corner cases.

The libraries available for writing tests are the following.

  • HUnit helps with writing unit in the spirit of JUnit.

  • HSpec integrates with HUnit and provides text-based combinators such as shouldBe instead of @=?.

  • QuickCheck provides helpers for generating random input data and defining property tests.

  • SmallCheck is similar to QuickCheck but focuses on exhaustively checking all "small" instances of a type. This may not scale well if a type has too many small instances

Organizing Tests

A large project will contain several test cases grouped into several test suites. There are many Haskell libraries that provide ways to organize such tests, in two main styles.

  • Explicit suite management, where lists or trees of test suites are written in the Haskell source files.
  • Test discovery, where some framework traverses the Haskell source files collecting the existing tests.

In the following subsections we discuss the available options. Note that QuickCheck and SmallCheck don't provide any utilities for organizing tests.

HUnit

HUnit allows explicit management, but it is not the focus of this library. The data constructors TestList and TestLabel allow tests to be grouped. Some operators like ~: and list are provided to try and make it more readable. Those who dislike too many operators will find it unpleasant.

Furthermore, this only allows HUnit tests to be grouped, so integration with property testing is difficult.

HSpec

HSpec allows explicit management, and its extension hspec-discover provides test discovery. It integrates with QuickCheck, SmallCheck and HUnit, and allows parallel test execution. It has pretty good documentation.

The main focus of HSpec is test management. It provides a DSL for describing test suites, and allows integration with property testing, as may be seen in this example.

Its test discovery tools, hspec-discover will scan the filesystem to find spec files, which must end in Spec.hs should export a variable spec :: Spec, as explained in its documentation.

Tasty

Tasty is a test organization tool that integrates with many other utilities including HUnit, HSpec, QuickCheck and SmallCheck. It also has an extension tasty-discover providing test discovery. It allows parallel test execution and may generate different outputs such as HTML or CSV reports. It also has very good documentation.

For manual test management, tasty allows the user to define trees of test cases as shown in this example.

Its test discovery tool will scan the files ending in Test.hs (or some other suffix, it's configurable). It will gather for top-level definitions such as:

  • QuickCheck properties prop_* :: QuickCheck.Property,
  • SmallCheck properties scprop_* :: SmallCheck.Property,
  • HUnit test cases unit_* :: HUnit.Test,
  • HSpec specifications spec_* :: Spec,
  • Tasty test trees test_* :: TestTree.

test-framework

test-framework is an older, less maintained utility for manual test management similar to tasty.

HTF

HTF is a test discovery tool for QuickCheck and HUnit tests. Older, less documented and requires every test module to begin with the following lines.

{-# OPTIONS_GHC -F -pgmF htfpp #-}
module Foo ( {- other exports... -}, htf_thisModuleTests ) where
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment