tasty

repository·master·Indexed 20 days ago

https://github.com/unkindpartition/tasty

A modern, extensible testing framework for Haskell that combines multiple testing styles—including unit, property, and golden tests—into a single hierarchical suite. It features parallel execution, deterministic reporting, resource management, and test filtering via awk-like patterns. The framework is extensible through providers (e.g., tasty-hunit, tasty-quickcheck) and ingredients for custom reporting and handling.

Tokens
3.6K
Snippets
8
Records
17
Agent score
21%

What's inside tasty

  1. Overview of Tasty testing framework

    master

    Tasty is a modern Haskell testing framework designed to combine various test types—such as unit tests, golden tests, and property-based tests (QuickCheck/SmallCheck)—into a single, unified test suite.

    Key features include:

    • Parallel Execution: Runs tests in parallel while reporting results in a deterministic order.
    • Test Filtering: Allows filtering tests via command-line patterns.
    • Hierarchical Reporting: Provides colored, hierarchical displays of test results and statistics.
    • Resource Management: Supports acquiring and releasing shared resources (e.g., sockets, temporary files) across multiple tests.
    • Extensibility: Allows users to add custom providers and ingredients.
  2. Filter tests using patterns

    master

    Use the -p|--pattern PATTERN option to restrict which tests are executed. Patterns are awk expressions evaluated against the test hierarchy.

    How patterns work

    When evaluating a pattern, Tasty provides the following fields:

    • $0: The full test name (all groups and the test name concatenated with .).
    • $1, $2, ... $NF: Individual components of the hierarchy (outermost group is $1, the test's own name is $NF).
    • NF: The total number of components in the hierarchy.

    Example Hierarchy

    For a test defined as: testGroup "One" [ testGroup "Two" [ testCase "Three" _ ] ]

    The fields are:

    • $0 = "One.Two.Three"
    • $1 = "One"
    • $2 = "Two"
    • $3 = "Three"
    • NF = 3

    Common Pattern Examples

    • foo: Shortcut for /foo/ (matches foo anywhere in $0).
    • $2 == "Two": Selects the subgroup named "Two".
    • $0 !~ /skip/: Selects tests whose full name does not contain "skip".
    • $NF !~ /skip/: Selects tests whose own name (not group name) does not contain "skip".
    • $(NF-1) ~ /QuickCheck/: Selects tests whose immediate parent group name contains "QuickCheck".

    Supported Operators and Functions

    Tasty supports standard awk operators including grouping (), field reference $, logical !, &&, ||, arithmetic +, -, string concatenation, and comparison ==, !=, <, <=, >, >=.

    It also supports substring matching ~ and !~ (e.g., $1 ~ /foo/), though it does not implement full regular expression matching (it performs a case-sensitive substring search).

    Built-in functions:

    • substr(s, m[, n]): Substring starting at position m with length n.
    • tolower(s) / toupper(s): Case conversion.
    • match(s, pat): Returns the 1-based position of pat in s.
    • length([s]): Returns string length.
    # Examples of pattern usage
    ./test -p foo              # Matches any test with 'foo' in the name
    ./test -p '$2 == "Two"'   # Selects subgroup 'Two'
    ./test -p '! /skip/'       # Excludes tests containing 'skip'
  3. How Tasty Ingredients work

    master

    In Tasty, Ingredients represent actions performed on a test suite. While providers define the tests themselves, ingredients define how those tests are handled or reported.

    Standard ingredients include:

    • Running tests and reporting progress/results.
    • Printing only the names of all tests.

    Common enhancement ingredients include:

    • tasty-ant-xml: Writes results in machine-readable XML for CI/CD.
    • tasty-rerun: Supports minimal reruns (e.g., only running failed tests).
    • tasty-html: Writes results as an HTML file.
    • tasty-stats: Collects test suite statistics in a CSV file.

    Custom ingredients can be written using the Test.Tasty.Runners API.

  4. Implement custom Tasty options

    master

    To extend Tasty with your own configuration options, follow these three steps:

    1. Define a datatype to represent your option and make it an instance of IsOption.
    2. Register the options with the includingOptions ingredient.
    3. Query the value during test execution using askOption.
  5. Create a test suite with Tasty

    master

    To create a test suite, you define a TestTree (often using testGroup to organize tests hierarchically) and pass it to defaultMain from Test.Tasty. You will typically import specific providers for the types of tests you are running (e.g., Test.Tasty.HUnit for unit tests or Test.Tasty.QuickCheck for property tests).

    import Test.Tasty
    import Test.Tasty.SmallCheck as SC
    import Test.Tasty.QuickCheck as QC
    import Test.Tasty.HUnit
    
    import Data.List
    import Data.Ord
    
    main = defaultMain tests
    
    tests :: TestTree
    tests = testGroup "Tests" [properties, unitTests]
    
    properties :: TestTree
    properties = testGroup "Properties" [scProps, qcProps]
    
    scProps = testGroup "(checked by SmallCheck)"
      [ SC.testProperty "sort == sort . reverse" $
          \list -> sort (list :: [Int]) == sort (reverse list)
      ]
    
    qcProps = testGroup "(checked by QuickCheck)"
      [ QC.testProperty "sort == sort . reverse" $
          \list -> sort (list :: [Int]) == sort (reverse list)
      ]
    
    unitTests = testGroup "Unit tests"
      [ testCase "List comparison (different length)" $
          [1, 2, 3] `compare` [1,2] @?= GT
      ]
  6. Migrate from test-framework to tasty

    master

    To migrate a project from test-framework to tasty, perform the following mechanical changes:

    Featuretest-frameworktasty
    Cabal Dependenciestest-framework, test-framework-hunit, test-framework-quickcheck2tasty, tasty-hunit, tasty-quickcheck
    Module ImportsTest.Framework, Test.Framework.Providers.HUnit, Test.Framework.Providers.QuickCheck2Test.Tasty, Test.Tasty.HUnit, Test.Tasty.QuickCheck
    Type SignaturesTestTestTree
    Main EntrypointdefaultMain testsdefaultMain (testGroup "All" tests)
  7. Set Tasty options at runtime via CLI or Environment Variables

    master

    You can customize the behavior of your test suite (e.g., mode of operation, test selection, provider parameters) using the standard console runner.

    Command Line Interface

    Run your test executable with the --help flag to see all available options for your specific configuration of ingredients and providers.

    Common CLI options include:

    • -p|--pattern PATTERN: Select tests satisfying an awk expression.
    • -t|--timeout DURATION: Set timeout for individual tests (suffixes: ms, s, m, h; default: s).
    • -l|--list-tests: List test names without running them.
    • -j|--num-threads NUMBER: Number of threads for execution.
    • -q|--quiet: No output; exit code indicates success/failure.
    • --hide-successes: Only print failed tests.
    • --color <never|always|auto>: Control colored output.

    Environment Variables

    Every option can be set via environment variables. To derive the variable name:

    1. Replace hyphens - with underscores _.
    2. Capitalize all letters.
    3. Prepend TASTY_.

    Example: --smallcheck-depth becomes TASTY_SMALLCHECK_DEPTH.

    Note on Boolean Options: When using the CLI, boolean options are switches (e.g., --quickcheck-show-replay). When using environment variables, you must provide an explicit True or False value (case-insensitive), e.g., TASTY_QUICKCHECK_SHOW_REPLAY=true.

    # Example of running with a timeout via CLI
    ./test --timeout=0.5m
  8. Run Tasty tests in parallel

    master

    To enable parallel test execution, you must perform two steps:

    1. Compile (link) your test program with the -threaded flag.
    2. Launch the resulting program using the GHC runtime system flag: +RTS -N -RTS.
    # Example compilation and execution
    ghc -threaded MyTests.hs
    ./MyTests +RTS -N -RTS
  9. Automatic Test Discovery

    master

    By default, Tasty requires you to explicitly construct your TestTree. If you prefer to write tests at the top-level and have them automatically collected, use one of the following discovery packages:

    • tasty-th
    • tasty-discover
    • tasty-autocollect
  10. Organize Tasty tests in a Cabal project

    master

    For library projects, it is recommended to place test sources in a dedicated tests/ subdirectory. The test.hs file should contain your main function.

    To integrate with Cabal, add a test-suite section to your .cabal file. Ensure you include tasty in your build-depends.

    test-suite test
      default-language:
        Haskell2010
      type:
        exitcode-stdio-1.0
      hs-source-dirs:
        tests
      main-is:
        test.hs
      build-depends:
          base >= 4 && < 5
        , tasty >= 0.7
        , my-project
  11. Troubleshoot garbled console output

    master

    If your tests write to stdout or stderr, the output may appear garbled when using the default console test reporter.

    Workarounds:

    • Use testCaseSteps (available in tasty-hunit).
    • Use a non-console reporter, such as tasty-ant-xml.
    • Redirect output to files instead of the console.
  12. Fix slash patterns on Windows

    master

    On Windows, Git for Windows or MinGW bash may convert slashes in patterns to backslashes, breaking Tasty patterns. To prevent this, set the following environment variables:

    • For Git for Windows terminal: MSYS_NO_PATHCONV=1
    • For MinGW bash: MSYS2_ARG_CONV_EXCL=*