Blame README.md

Packit b7c5e3
# Tasty
Packit b7c5e3
Packit b7c5e3
**Tasty** is a modern testing framework for Haskell.
Packit b7c5e3
Packit b7c5e3
It lets you combine your unit tests, golden tests, QuickCheck/SmallCheck
Packit b7c5e3
properties, and any other types of tests into a single test suite.
Packit b7c5e3
Packit b7c5e3
Features:
Packit b7c5e3
Packit b7c5e3
* Run tests in parallel but report results in a deterministic order
Packit b7c5e3
* Filter the tests to be run using patterns specified on the command line
Packit b7c5e3
* Hierarchical, colored display of test results
Packit b7c5e3
* Reporting of test statistics
Packit b7c5e3
* Acquire and release resources (sockets, temporary files etc.) that can be
Packit b7c5e3
  shared among several tests
Packit b7c5e3
* Extensibility: add your own test providers and ingredients (runners) above and
Packit b7c5e3
  beyond those provided
Packit b7c5e3
Packit b7c5e3
To find out what's new, read the **[change log][]**.
Packit b7c5e3
Packit b7c5e3
[change log]: https://github.com/feuerbach/tasty/blob/master/core/CHANGELOG.md
Packit b7c5e3
Packit b7c5e3
## Example
Packit b7c5e3
Packit b7c5e3
Here's how your `test.hs` might look like:
Packit b7c5e3
Packit b7c5e3
```haskell
Packit b7c5e3
import Test.Tasty
Packit b7c5e3
import Test.Tasty.SmallCheck as SC
Packit b7c5e3
import Test.Tasty.QuickCheck as QC
Packit b7c5e3
import Test.Tasty.HUnit
Packit b7c5e3
Packit b7c5e3
import Data.List
Packit b7c5e3
import Data.Ord
Packit b7c5e3
Packit b7c5e3
main = defaultMain tests
Packit b7c5e3
Packit b7c5e3
tests :: TestTree
Packit b7c5e3
tests = testGroup "Tests" [properties, unitTests]
Packit b7c5e3
Packit b7c5e3
properties :: TestTree
Packit b7c5e3
properties = testGroup "Properties" [scProps, qcProps]
Packit b7c5e3
Packit b7c5e3
scProps = testGroup "(checked by SmallCheck)"
Packit b7c5e3
  [ SC.testProperty "sort == sort . reverse" $
Packit b7c5e3
      \list -> sort (list :: [Int]) == sort (reverse list)
Packit b7c5e3
  , SC.testProperty "Fermat's little theorem" $
Packit b7c5e3
      \x -> ((x :: Integer)^7 - x) `mod` 7 == 0
Packit b7c5e3
  -- the following property does not hold
Packit b7c5e3
  , SC.testProperty "Fermat's last theorem" $
Packit b7c5e3
      \x y z n ->
Packit b7c5e3
        (n :: Integer) >= 3 SC.==> x^n + y^n /= (z^n :: Integer)
Packit b7c5e3
  ]
Packit b7c5e3
Packit b7c5e3
qcProps = testGroup "(checked by QuickCheck)"
Packit b7c5e3
  [ QC.testProperty "sort == sort . reverse" $
Packit b7c5e3
      \list -> sort (list :: [Int]) == sort (reverse list)
Packit b7c5e3
  , QC.testProperty "Fermat's little theorem" $
Packit b7c5e3
      \x -> ((x :: Integer)^7 - x) `mod` 7 == 0
Packit b7c5e3
  -- the following property does not hold
Packit b7c5e3
  , QC.testProperty "Fermat's last theorem" $
Packit b7c5e3
      \x y z n ->
Packit b7c5e3
        (n :: Integer) >= 3 QC.==> x^n + y^n /= (z^n :: Integer)
Packit b7c5e3
  ]
Packit b7c5e3
Packit b7c5e3
unitTests = testGroup "Unit tests"
Packit b7c5e3
  [ testCase "List comparison (different length)" $
Packit b7c5e3
      [1, 2, 3] `compare` [1,2] @?= GT
Packit b7c5e3
Packit b7c5e3
  -- the following test does not hold
Packit b7c5e3
  , testCase "List comparison (same length)" $
Packit b7c5e3
      [1, 2, 3] `compare` [1,2,2] @?= LT
Packit b7c5e3
  ]
Packit b7c5e3
```
Packit b7c5e3
Packit b7c5e3
And here is the output of the above program:
Packit b7c5e3
Packit b7c5e3
![](https://raw.github.com/feuerbach/tasty/master/screenshot.png)
Packit b7c5e3
Packit b7c5e3
(Note that whether QuickCheck finds a counterexample to the third property is
Packit b7c5e3
determined by chance.)
Packit b7c5e3
Packit b7c5e3
## Packages
Packit b7c5e3
Packit b7c5e3
[tasty][] is the core package. It contains basic definitions and APIs and a
Packit b7c5e3
console runner.
Packit b7c5e3
Packit b7c5e3
[tasty]: http://hackage.haskell.org/package/tasty
Packit b7c5e3
Packit b7c5e3
In order to create a test suite, you also need to install one or more «providers» (see
Packit b7c5e3
below).
Packit b7c5e3
Packit b7c5e3
### Providers
Packit b7c5e3
Packit b7c5e3
The following providers exist:
Packit b7c5e3
Packit b7c5e3
* [tasty-hunit](http://hackage.haskell.org/package/tasty-hunit) — for unit tests
Packit b7c5e3
  (based on [HUnit](http://hackage.haskell.org/package/HUnit))
Packit b7c5e3
* [tasty-golden][] — for golden
Packit b7c5e3
  tests, which are unit tests whose results are kept in files
Packit b7c5e3
* [tasty-smallcheck](http://hackage.haskell.org/package/tasty-smallcheck) —
Packit b7c5e3
  exhaustive property-based testing
Packit b7c5e3
  (based on [smallcheck](http://hackage.haskell.org/package/smallcheck))
Packit b7c5e3
* [tasty-quickcheck](http://hackage.haskell.org/package/tasty-quickcheck) — for randomized
Packit b7c5e3
  property-based testing (based on [QuickCheck](http://hackage.haskell.org/package/QuickCheck))
Packit b7c5e3
* [tasty-hedgehog](https://github.com/qfpl/tasty-hedgehog) — for randomized
Packit b7c5e3
  property-based testing (based on [Hedgehog](http://hackage.haskell.org/package/hedgehog))
Packit b7c5e3
* [tasty-hspec](http://hackage.haskell.org/package/tasty-hspec) — for
Packit b7c5e3
  [Hspec](http://hspec.github.io/) tests
Packit b7c5e3
* [tasty-program](http://hackage.haskell.org/package/tasty-program) — run
Packit b7c5e3
  external program and test whether it terminates successfully
Packit b7c5e3
Packit b7c5e3
[tasty-golden]: http://hackage.haskell.org/package/tasty-golden
Packit b7c5e3
Packit b7c5e3
It's easy to create custom providers using the API from `Test.Tasty.Providers`.
Packit b7c5e3
Packit b7c5e3
### Ingredients
Packit b7c5e3
Packit b7c5e3
Ingredients represent different actions that you can perform on your test suite.
Packit b7c5e3
One obvious ingredient that you want to include is one that runs tests and
Packit b7c5e3
reports the progress and results.
Packit b7c5e3
Packit b7c5e3
Another standard ingredient is one that simply prints the names of all tests.
Packit b7c5e3
Packit b7c5e3
It is possible to write custom ingredients using the API from `Test.Tasty.Runners`.
Packit b7c5e3
Packit b7c5e3
Some ingredients that can enhance your test suite are:
Packit b7c5e3
Packit b7c5e3
* [tasty-ant-xml](http://hackage.haskell.org/package/tasty-ant-xml) adds a
Packit b7c5e3
  possibility to write the test results in a machine-readable XML format, which
Packit b7c5e3
  is understood by various CI systems and IDEs
Packit b7c5e3
* [tasty-rerun](http://hackage.haskell.org/package/tasty-rerun) adds support for
Packit b7c5e3
  minimal test reruns by recording previous test runs and using this information
Packit b7c5e3
  to filter the test tree. For example, you can use this ingredient to only run
Packit b7c5e3
  failed tests, or only run tests that threw an exception.
Packit b7c5e3
* [tasty-html](http://hackage.haskell.org/package/tasty-html) adds the
Packit b7c5e3
  possibility to write the test results as a HTML file
Packit b7c5e3
* [tasty-stats](http://hackage.haskell.org/package/tasty-stats) adds the
Packit b7c5e3
  possibility to collect statistics of the test suite in a CSV file.
Packit b7c5e3
Packit b7c5e3
### Other packages
Packit b7c5e3
Packit b7c5e3
* [tasty-th](http://hackage.haskell.org/package/tasty-th) automatically
Packit b7c5e3
discovers tests based on the function names and generate the boilerplate code for
Packit b7c5e3
you
Packit b7c5e3
* [tasty-hunit-adapter](http://hackage.haskell.org/package/tasty-hunit-adapter)
Packit b7c5e3
  converts existing HUnit test suites into tasty test suites
Packit b7c5e3
* [tasty-discover](https://github.com/lwm/tasty-discover) automatically discovers
Packit b7c5e3
your tests.
Packit b7c5e3
* [tasty-expected-failure](https://github.com/nomeata/tasty-expected-failure) provides
Packit b7c5e3
test markers for when you expect failures or wish to ignore tests.
Packit b7c5e3
Packit b7c5e3
Packit b7c5e3
## Options
Packit b7c5e3
Packit b7c5e3
Options allow one to customize the run-time behavior of the test suite, such
Packit b7c5e3
as:
Packit b7c5e3
Packit b7c5e3
* mode of operation (run tests, list tests, run tests quietly etc.)
Packit b7c5e3
* which tests are run (see «Patterns» below)
Packit b7c5e3
* parameters of individual providers (like depth of search for SmallCheck)
Packit b7c5e3
Packit b7c5e3
### Setting options
Packit b7c5e3
Packit b7c5e3
There are two main ways to set options:
Packit b7c5e3
Packit b7c5e3
#### Runtime
Packit b7c5e3
Packit b7c5e3
When using the standard console runner, the options can be passed on the
Packit b7c5e3
command line or via environment variables. To see the available options, run
Packit b7c5e3
your test suite with the `--help` flag. The output will look something like this
Packit b7c5e3
(depending on which ingredients and providers the test suite uses):
Packit b7c5e3
Packit b7c5e3
```
Packit b7c5e3
% ./test --help
Packit b7c5e3
Mmm... tasty test suite
Packit b7c5e3
Packit b7c5e3
Usage: test [-p|--pattern ARG] [-t|--timeout ARG] [-l|--list-tests]
Packit b7c5e3
            [-j|--num-threads ARG] [-q|--quiet] [--hide-successes] [--color ARG]
Packit b7c5e3
            [--quickcheck-tests ARG] [--quickcheck-replay ARG]
Packit b7c5e3
            [--quickcheck-show-replay ARG] [--quickcheck-max-size ARG]
Packit b7c5e3
            [--quickcheck-max-ratio ARG] [--quickcheck-verbose]
Packit b7c5e3
            [--smallcheck-depth ARG]
Packit b7c5e3
Packit b7c5e3
Available options:
Packit b7c5e3
  -h,--help                Show this help text
Packit b7c5e3
  -p,--pattern ARG         Select only tests that match pattern
Packit b7c5e3
  -t,--timeout ARG         Timeout for individual tests (suffixes: ms,s,m,h;
Packit b7c5e3
                           default: s)
Packit b7c5e3
  -l,--list-tests          Do not run the tests; just print their names
Packit b7c5e3
  -j,--num-threads ARG     Number of threads to use for tests execution
Packit b7c5e3
  -q,--quiet               Do not produce any output; indicate success only by
Packit b7c5e3
                           the exit code
Packit b7c5e3
  --hide-successes         Do not print tests that passed successfully
Packit b7c5e3
  --color ARG              When to use colored output. Options are 'never',
Packit b7c5e3
                           'always' and 'auto' (default: 'auto')
Packit b7c5e3
  --quickcheck-tests ARG   Number of test cases for QuickCheck to generate
Packit b7c5e3
  --quickcheck-replay ARG  Replay token to use for replaying a previous test run
Packit b7c5e3
  --quickcheck-show-replay ARG
Packit b7c5e3
                           Show a replay token for replaying tests
Packit b7c5e3
  --quickcheck-max-size ARG
Packit b7c5e3
                           Size of the biggest test cases quickcheck generates
Packit b7c5e3
  --quickcheck-max-ratio ARG
Packit b7c5e3
                           Maximum number of discared tests per successful test
Packit b7c5e3
                           before giving up
Packit b7c5e3
  --quickcheck-verbose     Show the generated test cases
Packit b7c5e3
  --smallcheck-depth ARG   Depth to use for smallcheck tests
Packit b7c5e3
```
Packit b7c5e3
Packit b7c5e3
Every option can be passed via environment. To obtain the environment variable
Packit b7c5e3
name from the option name, replace hyphens `-` with underscores `_`, capitalize
Packit b7c5e3
all letters, and prepend `TASTY_`. For example, the environment equivalent of
Packit b7c5e3
`--smallcheck-depth` is `TASTY_SMALLCHECK_DEPTH`. To turn on a switch (such as
Packit b7c5e3
`TASTY_HIDE_SUCCESSES`), set the variable to `True`.
Packit b7c5e3
Packit b7c5e3
If you're using a non-console runner, please refer to its documentation to find
Packit b7c5e3
out how to configure options during the run time.
Packit b7c5e3
Packit b7c5e3
#### Compile-time
Packit b7c5e3
Packit b7c5e3
You can also specify options in the test suite itself, using
Packit b7c5e3
`localOption`. It can be applied not only to the whole test tree, but also to
Packit b7c5e3
individual tests or subgroups, so that different tests can be run with
Packit b7c5e3
different options.
Packit b7c5e3
Packit b7c5e3
It is possible to combine run-time and compile-time options, too, by using
Packit b7c5e3
`adjustOption`. For example, make the overall testing depth configurable
Packit b7c5e3
during the run time, but increase or decrease it slightly for individual
Packit b7c5e3
tests.
Packit b7c5e3
Packit b7c5e3
This method currently doesn't work for ingredient options, such as `--quiet` or
Packit b7c5e3
`--num-threads`. You can set them by setting the corresponding environment
Packit b7c5e3
variable before calling `defaultMain`:
Packit b7c5e3
Packit b7c5e3
Packit b7c5e3
Packit b7c5e3
```haskell
Packit b7c5e3
import Test.Tasty
Packit b7c5e3
import System.Environment
Packit b7c5e3
Packit b7c5e3
main = do
Packit b7c5e3
  setEnv "TASTY_NUM_THREADS" "1"
Packit b7c5e3
  defaultMain _
Packit b7c5e3
```
Packit b7c5e3
Packit b7c5e3
### Patterns
Packit b7c5e3
Packit b7c5e3
It is possible to restrict the set of executed tests using the `--pattern`
Packit b7c5e3
option. The syntax of patterns is the same as for test-framework, namely:
Packit b7c5e3
Packit b7c5e3
-   An optional prefixed bang `!` negates the pattern.
Packit b7c5e3
-   If the pattern ends with a slash, it is removed for the purpose of
Packit b7c5e3
    the following description, but it would only find a match with a
Packit b7c5e3
    test group. In other words, `foo/` will match a group called `foo`
Packit b7c5e3
    and any tests underneath it, but will not match a regular test
Packit b7c5e3
    `foo`.
Packit b7c5e3
-   If the pattern does not contain a slash `/`, the framework checks
Packit b7c5e3
    for a match against any single component of the path.
Packit b7c5e3
-   Otherwise, the pattern is treated as a glob, where:
Packit b7c5e3
    -   The wildcard `*` matches anything within a single path component
Packit b7c5e3
        (i.e. `foo` but not `foo/bar`).
Packit b7c5e3
    -   Two wildcards `**` matches anything (i.e. `foo` and `foo/bar`).
Packit b7c5e3
    -   Anything else matches exactly that text in the path (i.e. `foo`
Packit b7c5e3
        would only match a component of the test path called `foo` (or a
Packit b7c5e3
        substring of that form).
Packit b7c5e3
Packit b7c5e3
For example, `group/*1` matches `group/test1` but not
Packit b7c5e3
`group/subgroup/test1`, whereas both examples would be matched by
Packit b7c5e3
`group/**1`. A leading slash matches the beginning of the test path; for
Packit b7c5e3
example, `/test*` matches `test1` but not `group/test1`.
Packit b7c5e3
Packit b7c5e3
### Running tests in parallel
Packit b7c5e3
Packit b7c5e3
In order to run tests in parallel, you have to do the following:
Packit b7c5e3
Packit b7c5e3
* Compile (or, more precisely, *link*) your test program with the `-threaded`
Packit b7c5e3
  flag;
Packit b7c5e3
* Launch the program with `+RTS -N -RTS`.
Packit b7c5e3
Packit b7c5e3
### Timeout
Packit b7c5e3
Packit b7c5e3
To apply timeout to individual tests, use the `--timeout` (or `-t`) command-line
Packit b7c5e3
option, or set the option in your test suite using the `mkTimeout` function.
Packit b7c5e3
Packit b7c5e3
Timeouts can be fractional, and can be optionally followed by a suffix `ms`
Packit b7c5e3
(milliseconds), `s` (seconds), `m` (minutes), or `h` (hours). When there's no
Packit b7c5e3
suffix, seconds are assumed.
Packit b7c5e3
Packit b7c5e3
Example:
Packit b7c5e3
Packit b7c5e3
    ./test --timeout=0.5m
Packit b7c5e3
Packit b7c5e3
sets a 30 seconds timeout for each individual test.
Packit b7c5e3
Packit b7c5e3
### Options controlling console output
Packit b7c5e3
Packit b7c5e3
The following options control behavior of the standard console interface:
Packit b7c5e3
Packit b7c5e3
Packit b7c5e3
-q,--quiet
Packit b7c5e3
Packit b7c5e3
  Run the tests but don't output anything. The result is indicated only by the
Packit b7c5e3
  exit code, which is 1 if at least one test has failed, and 0 if all tests
Packit b7c5e3
  have passed. Execution stops when the first failure is detected, so not all
Packit b7c5e3
  tests are necessarily run.
Packit b7c5e3
  This may be useful for various batch systems, such as commit hooks.
Packit b7c5e3
Packit b7c5e3
--hide-successes
Packit b7c5e3
Report only the tests that has failed. Especially useful when the
Packit b7c5e3
number of tests is large.
Packit b7c5e3
-l,--list-tests
Packit b7c5e3
Don't run the tests; only list their names, in the format accepted by
Packit b7c5e3
--pattern.
Packit b7c5e3
--color
Packit b7c5e3
Whether to produce colorful output. Accepted values: never,
Packit b7c5e3
always, auto. auto means that colors will
Packit b7c5e3
only be enabled when output goes to a terminal and is the default value.
Packit b7c5e3
Packit b7c5e3
Packit b7c5e3
### Custom options
Packit b7c5e3
Packit b7c5e3
It is possible to add custom options, too.
Packit b7c5e3
Packit b7c5e3
To do that,
Packit b7c5e3
Packit b7c5e3
1. Define a datatype to represent the option, and make it an instance of
Packit b7c5e3
   `IsOption`
Packit b7c5e3
2. Register the options with the `includingOptions` ingredient
Packit b7c5e3
3. To query the option value, use `askOption`.
Packit b7c5e3
Packit b7c5e3
See the [Custom options in Tasty][custom-options-article] article for some examples.
Packit b7c5e3
Packit b7c5e3
## Project organization and integration with Cabal
Packit b7c5e3
Packit b7c5e3
There may be several ways to organize your project. What follows is not
Packit b7c5e3
Tasty's requirements but my recommendations.
Packit b7c5e3
Packit b7c5e3
### Tests for a library
Packit b7c5e3
Packit b7c5e3
Place your test suite sources in a dedicated subdirectory (called `tests`
Packit b7c5e3
here) instead of putting them among the main library sources.
Packit b7c5e3
Packit b7c5e3
The directory structure will be as follows:
Packit b7c5e3
Packit b7c5e3
    my-project/
Packit b7c5e3
      my-project.cabal
Packit b7c5e3
      src/
Packit b7c5e3
        ...
Packit b7c5e3
      tests/
Packit b7c5e3
        test.hs
Packit b7c5e3
        Mod1.hs
Packit b7c5e3
        Mod2.hs
Packit b7c5e3
        ...
Packit b7c5e3
Packit b7c5e3
`test.hs` is where your `main` function is defined. The tests may be
Packit b7c5e3
contained in `test.hs` or spread across multiple modules (`Mod1.hs`, `Mod2.hs`,
Packit b7c5e3
...) which are then imported by `test.hs`.
Packit b7c5e3
Packit b7c5e3
Add the following section to the cabal file (`my-project.cabal`):
Packit b7c5e3
Packit b7c5e3
    test-suite test
Packit b7c5e3
      default-language:
Packit b7c5e3
        Haskell2010
Packit b7c5e3
      type:
Packit b7c5e3
        exitcode-stdio-1.0
Packit b7c5e3
      hs-source-dirs:
Packit b7c5e3
        tests
Packit b7c5e3
      main-is:
Packit b7c5e3
        test.hs
Packit b7c5e3
      build-depends:
Packit b7c5e3
          base >= 4 && < 5
Packit b7c5e3
        , tasty >= 0.7 -- insert the current version here
Packit b7c5e3
        , my-project   -- depend on the library we're testing
Packit b7c5e3
        , ...
Packit b7c5e3
Packit b7c5e3
### Tests for a program
Packit b7c5e3
Packit b7c5e3
All the above applies, except you can't depend on the library if there's no
Packit b7c5e3
library. You have two options:
Packit b7c5e3
Packit b7c5e3
* Re-organize the project into a library and a program, so that both the
Packit b7c5e3
  program and the test suite depend on this new library. The library can be
Packit b7c5e3
  declared in the same cabal file.
Packit b7c5e3
* Add your program sources directory to the `Hs-source-dirs`. Note that this
Packit b7c5e3
  will lead to double compilation (once for the program and once for the test
Packit b7c5e3
  suite).
Packit b7c5e3
Packit b7c5e3
## FAQ
Packit b7c5e3
Packit b7c5e3
1.  How do I make some tests execute after others?
Packit b7c5e3
Packit b7c5e3
    Currently, your only option is to make all tests execute sequentially by
Packit b7c5e3
    setting the number of tasty threads to 1 ([example](#num_threads_example)).
Packit b7c5e3
    See [#48](https://github.com/feuerbach/tasty/issues/48) for the discussion.
Packit b7c5e3
Packit b7c5e3
## Press
Packit b7c5e3
Packit b7c5e3
Blog posts and other publications related to tasty. If you wrote or just found
Packit b7c5e3
something not mentioned here, send a pull request!
Packit b7c5e3
Packit b7c5e3
* [Holy Haskell Project Starter](http://yannesposito.com/Scratch/en/blog/Holy-Haskell-Starter/)
Packit b7c5e3
* [First time testing, also with FP Complete](http://levischuck.com/posts/2013-11-13-first-testing-and-fpcomplete.html)
Packit b7c5e3
  (tasty has been added to stackage since then)
Packit b7c5e3
* [24 Days of Hackage: tasty](http://ocharles.org.uk/blog/posts/2013-12-03-24-days-of-hackage-tasty.html)
Packit b7c5e3
* [Resources in Tasty](http://ro-che.info/articles/2013-12-10-tasty-resources.html)
Packit b7c5e3
* [Custom options in Tasty][custom-options-article]
Packit b7c5e3
* [Resources in Tasty (update)](http://ro-che.info/articles/2013-12-29-tasty-resources-2.html)
Packit b7c5e3
* [Announcing tasty-rerun](http://ocharles.org.uk/blog/posts/2014-01-20-announcing-tasty-rerun.html)
Packit b7c5e3
* [Code testing in Haskell revisited (with Tasty)](http://lambda.jstolarek.com/2014/01/code-testing-in-haskell-revisited-with-tasty/)
Packit b7c5e3
Packit b7c5e3
[custom-options-article]: http://ro-che.info/articles/2013-12-20-tasty-custom-options.html
Packit b7c5e3
Packit b7c5e3
Maintainers
Packit b7c5e3
-----------
Packit b7c5e3
Packit b7c5e3
[Roman Cheplyaka](https://github.com/feuerbach) is the primary maintainer.
Packit b7c5e3
Packit b7c5e3
[Oliver Charles](https://github.com/ocharles) is the backup maintainer. Please
Packit b7c5e3
get in touch with him if the primary maintainer cannot be reached.