HORIZON HASKELLDocslts/ghc-9.10.xc74966e2026-09-27Search names, modules, packages, or :: a typeCtrl K

GHC 9.10.3 · lts/ghc-9.10.x · c74966e · 2026-09-27

Modulesydtest-0.22.0.0Haskell2010

Test.Syd

Modern testing of Haskell code using sydtest

For a full overview of features and comparisons, please see the README.

What's in a test

To use sydtest, you don't necessarily need to know the following, but for advanced usage you definitely will. If you're just starting out, you can ignore this section and just follow the examples in the docs below.

  • Every test is an instance of the IsTest type class. A test can be a pure Bool, an IO (), a GoldenTest, some combination of those, or any type that you can implement IsTest for.

  • sydtest allows you to declare resources for use during your tests. This could be things like a database connection or a server to connect to, for example.

  • Every resource is either an outer resource (set up once for a test group) or an inner resource (set up again for each test).

  • Every IsTest instance defines two associated types, an Arg1 type and an Arg2 type. These correspond to two function arguments. Arg1 corresponds to the first and Arg2 corresponds to the second. For example, IO () is an instance of IsTest, but arg -> IO () and outerArgs -> innerArg -> IO () are as well.

    • For outerArgs -> innerArgs -> IO (), Arg1 is outerArgs and Arg2 is innerArgs.

    • For arg -> IO (), Arg1 is () and Arg2 is arg.

    • For IO (), both Arg1 and Arg2 are ().

  • When using it or specify to define tests, the Arg1 and Arg2 arguments of the test that you pass in have to correspond to the outer and inner resources of your test suite, respectively.

  • You can declare how to set up or tear down resources using the around and aroundAll functions.

  • 22 types
  • 2 classes
  • 119 values
  • Packagesydtest-0.22.0.0
  • Exports143
  • LanguageHaskell2010
  • LicenceLicenseRef-OtherLicense
  • SourceSyd.hs

Top level API functions

2 declarations
valuesydTest :: Spec -> IO ()
#

Evaluate a test suite definition and then run it.

This function perform option-parsing to construct the Settings and then call sydTestWith.

Defining a test suite

0 declarations

Declaring tests

11 declarations
valuedescribe
  1. :: String

    The test group description

  2. -> TestDefM outers inner ()
  3. -> TestDefM outers inner ()
#

Declare a test group

Example usage:
describe "addition" $ do
    it "adds 3 to 5 to result in 8" $
        3 + 5 `shouldBe` 8
    it "adds 4 to 7 to result in 11" $
        4 + 7 `shouldBe` 11
valueit
  1. :: (HasCallStack, IsTest test, Arg1 test ~ (), Arg2 test ~ inner)
  2. => String

    The description of the test

  3. -> test

    The test itself

  4. -> TestDefM outers inner ()
#

Declare a test

Note: Don't look at the type signature unless you really have to, just follow the examples.

Example usage:
Tests without resources
Pure test
describe "addition" $
    it "adds 3 to 5 to result in 8" $
        3 + 5 == 8
IO test
describe "readFile and writeFile" $
    it "reads back what it wrote for this example" $ do
        let cts = "hello world"
        let fp = "test.txt"
        writeFile fp cts
        cts' <- readFile fp
        cts' `shouldBe` cts
Pure Property test
describe "sort" $
    it "is idempotent" $
        forAllValid $ \ls ->
            sort (sort ls) `shouldBe` (sort (ls :: [Int]))
IO Property test
describe "readFile and writeFile" $
    it "reads back what it wrote for any example" $ do
        forAllValid $ \fp ->
            forAllValid $ \cts -> do
                writeFile fp cts
                cts' <- readFile fp
                cts' `shouldBe` cts
Tests with an inner resource
Pure test

This is quite a rare use-case but here is an example anyway:

before (pure 3) $ describe "addition" $
    it "adds 3 to 5 to result in 8" $ \i ->
        i + 5 == 8
IO test

This test sets up a temporary directory as an inner resource, and makes it available to each test in the group below.

let setUpTempDir func = withSystemTempDir $ \tempDir -> func tempDir
in around setUpTempDir $ describe "readFile and writeFile" $
    it "reads back what it wrote for this example" $ \tempDir -> do
        let cts = "hello world"
        let fp = tempDir </> "test.txt"
        writeFile fp cts
        cts' <- readFile fp
        cts' `shouldBe` cts
Pure property test

This is quite a rare use-case but here is an example anyway:

before (pure 3) $ describe "multiplication" $
    it "is commutative for 5" $ \i ->
        i * 5 == 5 * 3
IO property test
let setUpTempDir func = withSystemTempDir $ \tempDir -> func tempDir
in around setUpTempDir $ describe "readFile and writeFile" $
    it "reads back what it wrote for this example" $ \tempDir ->
        property $ \cts -> do
            let fp = tempDir </> "test.txt"
            writeFile fp cts
            cts' <- readFile fp
            cts' `shouldBe` cts
valueitWithOuter
  1. :: (HasCallStack, IsTest test, Arg1 test ~ inner, Arg2 test ~ outer)
  2. => String
  3. -> test
  4. -> TestDefM (outer ': otherOuters) inner ()
#

Declare a test that uses an outer resource

Example usage:
Tests with an outer resource
Pure test

This is quite a rare use-case but here is an example anyway:

beforeAll (pure 3) $ describe "addition" $
    itWithOuter "adds 3 to 5 to result in 8" $ \i ->
        i + 5 == 8
IO test

This test sets up a temporary directory as an inner resource, and makes it available to each test in the group below.

let setUpTempDir func = withSystemTempDir $ \tempDir -> func tempDir
in aroundAll setUpTempDir describe "readFile and writeFile" $
    itWithOuter "reads back what it wrote for this example" $ \tempDir -> do
        let cts = "hello world"
        let fp = tempDir </> "test.txt"
        writeFile fp cts
        cts' <- readFile fp
        cts' `shouldBe` cts
Pure property test

This is quite a rare use-case but here is an example anyway:

beforeAll (pure 3) $ describe "multiplication" $
    itWithOuter "is commutative for 5" $ \i ->
        i * 5 == 5 * 3
IO property test
let setUpTempDir func = withSystemTempDir $ \tempDir -> func tempDir
in aroundAll setUpTempDir describe "readFile and writeFile" $
    itWithouter "reads back what it wrote for this example" $ \tempDir ->
        property $ \cts -> do
            let fp = tempDir </> "test.txt"
            writeFile fp cts
            cts' <- readFile fp
            cts' `shouldBe` cts
valueitWithBoth
  1. :: (HasCallStack, IsTest test, Arg1 test ~ outer, Arg2 test ~ inner)
  2. => String
  3. -> test
  4. -> TestDefM (outer ': otherOuters) inner ()
#

Declare a test that uses both an inner and an outer resource

Example usage:
Tests with both an inner and an outer resource
Pure test

This is quite a rare use-case but here is an example anyway:

beforeAll (pure 3) $ before (pure 5) $ describe "addition" $
    itWithBoth "adds 3 to 5 to result in 8" $ \i j ->
        i + j == 8
IO test

This test sets up a temporary directory as an inner resource, and makes it available to each test in the group below.

let setUpTempDir func = withSystemTempDir $ \tempDir -> func tempDir
in aroundAll setUpTempDir describe "readFile and writeFile" $ before (pure "hello world") $
    itWithBoth "reads back what it wrote for this example" $ \tempDir cts -> do
        let fp = tempDir </> "test.txt"
        writeFile fp cts
        cts' <- readFile fp
        cts' `shouldBe` cts
Pure property test

This is quite a rare use-case but here is an example anyway:

beforeAll (pure 3) $ before (pure 5) $ describe "multiplication" $
    itWithBoth "is commutative" $ \i j ->
        i * j == 5 * 3
IO property test
let setUpTempDir func = withSystemTempDir $ \tempDir -> func tempDir
in aroundAll setUpTempDir describe "readFile and writeFile" $ before (pure "test.txt") $
    itWithBoth "reads back what it wrote for this example" $ \tempDir fileName ->
        property $ \cts -> do
            let fp = tempDir </> fileName
            writeFile fp cts
            cts' <- readFile fp
            cts' `shouldBe` cts
valueitWithAll
  1. :: (HasCallStack, IsTest test, Arg1 test ~ HList outers, Arg2 test ~ inner)
  2. => String
  3. -> test
  4. -> TestDefM outers inner ()
#

Declare a test that uses all outer resources

You will most likely never need this function, but in case you do: Note that this will always require a type annotation, along with the GADTs and ScopedTypeVariables extensions.

Example usage
beforeAll (pure 'a') $ beforeAll (pure 5) $
    itWithAll "example" $
        \(HCons c (HCons i HNil) :: HList '[Char, Int]) () ->
            (c, i) `shouldeBe` ('a', 5)
valueprop :: Testable prop => String -> prop -> Spec
#

Convenience function for backwards compatibility with hspec

prop s p = it s $ property p
valuegetTestDescriptionPath :: TestDefM outers inner [Text]
#

Get the path of describe strings upwards.

Note that using this function makes tests less movable, depending on what you do with these strings. For example, if you use these strings to define the path to a golden test file, then that path will change if you move the tests somewhere else. This combines unfortunately with the way sydtest-discover makes the module name part of this path. Indeed: moving your tests to another module will change their path as well, if you use sydtest-discover. Also note that while test forests can be randomised, their description path upwards will not, because of how trees are structured.

Commented-out tests

Pending tests

Golden tests

The golden test context for adding context to a golden test assertion:

goldenTestCompare = \actual expected ->
  if actual == expected
    then Nothing
    else Just $ Context (stringsNotEqualButShouldHaveBeenEqual actual expected) (goldenContext fp)
datadata GoldenTest a
#

A golden test for output of type a.

The purpose of a golden test is to ensure that the output of a certain process does not change even over time.

Golden tests can also be used to show how the output of a certain process changes over time and force code reviewers to review the diff that they see in the PR.

This works by saving a golden output in the repository somewhere, committing it, and then compare that golden output to the output that is currently being produced. You can use `--golden-reset` to have sydtest update the golden output by writing the current output.

Constructors

Instances18IsTest, Arg1, Arg2, …
  • IsTest (IO (GoldenTest a))Defined in sydtest-0.22.0.0 · Test.Syd.Run
  • IsTest (GoldenTest a)Defined in sydtest-0.22.0.0 · Test.Syd.Run
  • IsTest (arg -> IO (GoldenTest a))Defined in sydtest-0.22.0.0 · Test.Syd.Run
  • IsTest (arg -> GoldenTest a)Defined in sydtest-0.22.0.0 · Test.Syd.Run
  • IsTest (outerArgs -> innerArg -> IO (GoldenTest a))Defined in sydtest-0.22.0.0 · Test.Syd.Run
  • IsTest (outerArgs -> innerArg -> GoldenTest a)Defined in sydtest-0.22.0.0 · Test.Syd.Run
  • type Arg1 (IO (GoldenTest a)) = ()Defined in sydtest-0.22.0.0 · Test.Syd.Run
  • type Arg1 (GoldenTest a) = ()Defined in sydtest-0.22.0.0 · Test.Syd.Run
  • type Arg1 (arg -> IO (GoldenTest a)) = ()Defined in sydtest-0.22.0.0 · Test.Syd.Run
  • type Arg1 (arg -> GoldenTest a) = ()Defined in sydtest-0.22.0.0 · Test.Syd.Run
  • type Arg1 (outerArgs -> innerArg -> IO (GoldenTest a)) = outerArgsDefined in sydtest-0.22.0.0 · Test.Syd.Run
  • type Arg1 (outerArgs -> innerArg -> GoldenTest a) = outerArgsDefined in sydtest-0.22.0.0 · Test.Syd.Run
  • type Arg2 (IO (GoldenTest a)) = ()Defined in sydtest-0.22.0.0 · Test.Syd.Run
  • type Arg2 (GoldenTest a) = ()Defined in sydtest-0.22.0.0 · Test.Syd.Run
  • type Arg2 (arg -> IO (GoldenTest a)) = argDefined in sydtest-0.22.0.0 · Test.Syd.Run
  • type Arg2 (arg -> GoldenTest a) = argDefined in sydtest-0.22.0.0 · Test.Syd.Run
  • type Arg2 (outerArgs -> innerArg -> IO (GoldenTest a)) = innerArgDefined in sydtest-0.22.0.0 · Test.Syd.Run
  • type Arg2 (outerArgs -> innerArg -> GoldenTest a) = innerArgDefined in sydtest-0.22.0.0 · Test.Syd.Run

Scenario tests

valuescenarioDir
  1. :: FilePath
  2. -> FilePath -> TestDefM outers inner ()
  3. -> TestDefM outers inner ()
#

Define a test for each file in the given directory.

Example:

  scenarioDir "test_resources/even" $ \fp ->
    it "contains an even number" $ do
      s <- readFile fp
      n <- readIO s
      (n :: Int) `shouldSatisfy` even
valuescenarioDirRecur
  1. :: FilePath
  2. -> FilePath -> TestDefM outers inner ()
  3. -> TestDefM outers inner ()
#

Define a test for each file in the given directory, recursively.

Example:

  scenarioDirRecur "test_resources/odd" $ \fp ->
    it "contains an odd number" $ do
      s <- readFile fp
      n <- readIO s
      (n :: Int) `shouldSatisfy` odd

Expectations

Make a test fail

Note that this is mostly backward compatible, but it has return type a instead of () because execution will not continue beyond this function. In this way it is not entirely backward compatible with hspec because now there could be an ambiguous type error.

valuecontext :: String -> IO a -> IO a
#

Annotate a given action with a context, for contextual assertions

This is a completely different function from the function with the same name in hspec. In hspec, context is a synonym for describe, but in sydtest, context is used for contextual failures.

String expectations

valuetextShouldBe :: HasCallStack => Text -> Text -> IO ()
#

Assert that two Texts are equal according to ==.

Note that using function could mess up the colours in your terminal if the Texts contain ANSI codes. In that case you may want to show your values first or use shouldBe instead.

For throwing raw assertions

datadata Assertion
#

A special exception that sydtest knows about and can display nicely in the error output

This is exported outwards so that you can define golden tests for custom types.

You will probably not want to use this directly in everyday tests, use shouldBe or a similar function instead.

Constructors

Instances5Eq, Show, Generic, Exception, Rep

Declaring test dependencies

Dependencies around all of a group of tests

valuebeforeAll
  1. :: IO outer

    The function to run (once), beforehand, to produce the outer resource.

  2. -> TestDefM (outer ': otherOuters) inner result
  3. -> TestDefM otherOuters inner result
#

Run a custom action before all spec items in a group, to set up an outer resource a.

valuebeforeAll_
  1. :: IO ()

    The function to run (once), beforehand.

  2. -> TestDefM outers inner result
  3. -> TestDefM outers inner result
#

Run a custom action before all spec items in a group without setting up any outer resources.

valuebeforeAllWith
  1. :: (previousOuter -> IO newOuter)

    The function to run (once), beforehand, to produce a new outer resource while using a previous outer resource

  2. -> TestDefM (newOuter ': previousOuter ': otherOuters) inner result
  3. -> TestDefM (previousOuter ': otherOuters) inner result
#

Run a custom action before all spec items in a group, to set up an outer resource b by using the outer resource a.

valueafterAll
  1. :: (outer -> IO ())

    The function to run (once), afterwards, using the outer resource.

  2. -> TestDefM (outer ': otherOuters) inner result
  3. -> TestDefM (outer ': otherOuters) inner result
#

Run a custom action after all spec items, using the outer resource a.

valueafterAll'
  1. :: (HList outers -> IO ())

    The function to run (once), afterwards, using all outer resources.

  2. -> TestDefM outers inner result
  3. -> TestDefM outers inner result
#

Run a custom action after all spec items, using all the outer resources.

valueafterAll_
  1. :: IO ()

    The function to run (once), afterwards.

  2. -> TestDefM outers inner result
  3. -> TestDefM outers inner result
#

Run a custom action after all spec items without using any outer resources.

valuearoundAll
  1. :: ((outer -> IO ()) -> IO ())

    The function that provides the outer resource (once), around the tests.

  2. -> TestDefM (outer ': otherOuters) inner result
  3. -> TestDefM otherOuters inner result
#

Run a custom action before and/or after all spec items in group, to provide access to a resource a.

See the FOOTGUN note in the docs for around_.

valuearoundAll_
  1. :: (IO () -> IO ())

    The function that wraps running the tests.

  2. -> TestDefM outers inner result
  3. -> TestDefM outers inner result
#

Run a custom action before and/or after all spec items in a group without accessing any resources.

FOOTGUN

This combinator gives the programmer a lot of power. In fact, it gives the programmer enough power to break the test framework. Indeed, you can provide a wrapper function that just _doesn't_ run the function like this:

spec :: Spec
spec = do
   let don'tDo :: IO () -> IO ()
       don'tDo _ = pure ()
   aroundAll_ don'tDo $ do
     it "should pass" True

During execution, you'll then get an error like this:

thread blocked indefinitely in an MVar operation

The same problem exists when using around_.

Something even more pernicious goes wrong when you run the given action more than once like this:

spec :: Spec
spec = do
   let doTwice :: IO () -> IO ()
       doTwice f = f >> f
   aroundAll_ doTwice $ do
     it "should pass" True

In this case, the test will "just work", but it will be executed twice even if the output reports that it only passed once.

Note: If you're interested in fixing this, talk to me, but only after GHC has gotten impredicative types because that will likely be a requirement.

valuearoundAllWith
  1. :: ((newOuter -> IO ()) -> oldOuter -> IO ())

    The function that provides the new outer resource (once), using the old outer resource.

  2. -> TestDefM (newOuter ': oldOuter ': otherOuters) inner result
  3. -> TestDefM (oldOuter ': otherOuters) inner result
#

Run a custom action before and/or after all spec items in a group to provide access to a resource a while using a resource b

See the FOOTGUN note in the docs for around_.

valuearoundAllWithAll
  1. :: ((newOuter -> IO ()) -> HList (oldOuter ': otherOuters) -> IO ())

    The function that provides the new outer resource (once), using the old outer resource.

  2. -> TestDefM (newOuter ': oldOuter ': otherOuters) inner result
  3. -> TestDefM (oldOuter ': otherOuters) inner result
#

Run a custom action before and/or after all spec items in a group to provide access to a resource a while using all outer resources.

Dependencies around each of a group of tests

valuearound_
  1. :: (IO () -> IO ())

    The function to wrap every test with

  2. -> TestDefM outers inner result
  3. -> TestDefM outers inner result
#

Run a custom action before and/or after every spec item without accessing any inner resources.

It is important that the wrapper function that you provide runs the action that it gets _exactly once_.

FOOTGUN

This combinator gives the programmer a lot of power. In fact, it gives the programmer enough power to break the test framework. Indeed, you can provide a wrapper function that just _doesn't_ run the function like this:

spec :: Spec
spec = do
   let don'tDo :: IO () -> IO ()
       don'tDo _ = pure ()
   around_ don'tDo $ do
     it "should pass" True

During execution, you'll then get an error like this:

thread blocked indefinitely in an MVar operation

The same problem exists when using Test.Syd.Def.Around.aroundAll_.

The same thing will go wrong if you run the given action more than once like this:

spec :: Spec
spec = do
   let doTwice :: IO () -> IO ()
       doTwice f = f >> f
   around_ doTwice $ do
     it "should pass" True

Note: If you're interested in fixing this, talk to me, but only after GHC has gotten impredicative types because that will likely be a requirement.

Note that this function turns off shrinking. See https://github.com/nick8325/quickcheck/issues/331

Setup functions

Creating setup functions

newtypenewtype SetupFunc resource
#

A function that can provide a resource.

You can think of this as a potentially-resource-aware version of 'IO resource'. In other words, it's like an 'IO resource' that can clean up after itself.

This type has a monad instance, which means you can now compose setup functions using regular do-notation. This works together nicely with most supplier functions. Some examples:

Note that these examples already have functions defined for them in sydtest companion libraries.

Constructors

Instances4Monad, Functor, Applicative, MonadIO

Using setup functions

Around

AroundAll

Declaring different test settings

datadata TestRunSettings
#
Instances4Eq, Show, Generic, Rep

Declaring parallelism

valueparallel :: TestDefM a b c -> TestDefM a b c
#

Declare that all tests below may be run in parallel. (This is the default.)

datadata Parallelism
#
Instances4Eq, Show, Generic, Rep

Declaring randomisation order

Instances4Eq, Show, Generic, Rep

Modifying the timeout

Modifying the number of retries

Declaring flakiness

valueflaky :: Word -> TestDefM a b c -> TestDefM a b c
#

Mark a test suite as "potentially flaky" with a given number of retries.

This will retry any test in the given test group up to the given number of tries, and pass a test if it passes once. The test output will show which tests were flaky.

WARNING: This is only a valid approach to dealing with test flakiness if it is true that tests never pass accidentally. In other words: tests using flaky must be guaranteed to fail every time if an error is introduced in the code, it should only be added to deal with accidental failures, never accidental passes.

valueflakyWith :: Word -> String -> TestDefM a b c -> TestDefM a b c
#

Like flaky, but also shows the given message to the user whenever the test is flaky.

You could use it like this:

Example1 expression
flakyWith 3 "Something sometimes goes wrong with the database, see issue 6346" ourTestSuite
valuenotFlaky :: TestDefM a b c -> TestDefM a b c
#

Mark a test suite as "must not be flaky".

This is useful to have a subgroup of a group marked as flaky that must not be flaky afteral.

valuepotentiallyFlaky :: TestDefM a b c -> TestDefM a b c
#

Mark a test suite as 'potentially flaky', such that it will not fail if it is flaky but passes at least once.

datadata FlakinessMode
#
Instances4Eq, Show, Generic, Rep

Declaring expectations

datadata ExpectationMode
#
Instances4Eq, Show, Generic, Rep

Doing IO during test definition

valuerunIO :: IO e -> TestDefM a b e
#

Run a test suite during test suite definition.

This function only exists for backward compatibility. You can also just use liftIO instead.

Test definition types

newtypenewtype TestDefM (outers :: [Type]) inner result
#

The test definition monad

This type has three parameters:

  • outers: A type-level list of the outer resources. These are resources that are prived once, around a group of tests. (This is the type of the results of aroundAll.)

  • inner: The inner resource. This is a resource that is set up around every test, and even every example of a property test. (This is the type of the result of around.)

  • result: The result (TestDefM is a monad.)

In practice, all of these three parameters should be () at the top level.

Constructors

Instances6MonadReader, Monad, Functor, Applicative, MonadIO, MonadWriter
typetype TestDef (outers :: [Type]) inner = TestDefM outers inner ()
#

A synonym for a test suite definition

classclass IsTest e where
#

Associated types

  • type family Arg1 e

    The argument from aroundAll

  • type family Arg2 e

    The argument from around

Methods

Instances20IsTest, …
  • IsTest PropertyDefined in sydtest-0.22.0.0 · Test.Syd.Run
  • IsTest BoolDefined in sydtest-0.22.0.0 · Test.Syd.Run
  • IsTest (IO (GoldenTest a))Defined in sydtest-0.22.0.0 · Test.Syd.Run
  • IsTest (IO ())Defined in sydtest-0.22.0.0 · Test.Syd.Run
  • IsTest (GoldenTest a)Defined in sydtest-0.22.0.0 · Test.Syd.Run
  • IsTest (StagedGolden a)Defined in sydtest-0.22.0.0 · Test.Syd.Run
  • IsTest (arg -> Property)Defined in sydtest-0.22.0.0 · Test.Syd.Run
  • IsTest (arg -> Bool)Defined in sydtest-0.22.0.0 · Test.Syd.Run
  • IsTest (arg -> IO (GoldenTest a))Defined in sydtest-0.22.0.0 · Test.Syd.Run
  • IsTest (arg -> IO ())Defined in sydtest-0.22.0.0 · Test.Syd.Run
  • IsTest (arg -> GoldenTest a)Defined in sydtest-0.22.0.0 · Test.Syd.Run
  • IsTest (arg -> StagedGolden a)Defined in sydtest-0.22.0.0 · Test.Syd.Run
  • IsTest (outerArgs -> ReaderT env IO ())Defined in sydtest-0.22.0.0 · Test.Syd.Run
  • IsTest (outerArgs -> innerArg -> Property)Defined in sydtest-0.22.0.0 · Test.Syd.Run
  • IsTest (outerArgs -> innerArg -> Bool)Defined in sydtest-0.22.0.0 · Test.Syd.Run
  • IsTest (outerArgs -> innerArg -> IO (GoldenTest a))Defined in sydtest-0.22.0.0 · Test.Syd.Run
  • IsTest (outerArgs -> innerArg -> IO ())Defined in sydtest-0.22.0.0 · Test.Syd.Run
  • IsTest (outerArgs -> innerArg -> GoldenTest a)Defined in sydtest-0.22.0.0 · Test.Syd.Run
  • IsTest (outerArgs -> innerArg -> StagedGolden a)Defined in sydtest-0.22.0.0 · Test.Syd.Run
  • IsTest (ReaderT env IO ())Defined in sydtest-0.22.0.0 · Test.Syd.Run

Test suite types

datadata SpecDefTree (outers :: [Type]) inner extra where
#

A tree of tests

This type has three parameters:

  • outers: A type-level list of the outer resources. These are resources that are prived once, around a group of tests. (This is the type of the results of aroundAll.)

  • inner: The inner resource. This is a resource that is set up around every test, and even every example of a property test. (This is the type of the result of around.)

  • result: The result (TestDefM is a monad.)

In practice, all of these three parameters should be () at the top level.

When you're just using sydtest and not writing a library for sydtest, you probably don't even want to concern yourself with this type.

Constructors

Instances4Functor, Foldable, Traversable, MonadWriter

Hspec synonyms

typetype Spec = SpecWith ()
#

A synonym for easy migration from hspec

typetype SpecWith inner = SpecM inner ()
#

A synonym for easy migration from hspec

typetype SpecM inner result = TestDefM '[] inner result
#

A synonym for easy migration from hspec

Utilities

2 declarations
valuepPrint :: Show a => a -> IO ()
#

Pretty print a generic value to stdout. This is particularly useful in the GHCi interactive environment.

Reexports

1 declaration
classclass Monad m => MonadIO (m :: Type -> Type) where
#

Monads in which IO computations may be embedded. Any monad built by applying a sequence of monad transformers to the IO monad will be an instance of this class.

Instances should satisfy the following laws, which state that liftIO is a transformer of monads:

Methods

  • liftIO :: IO a -> m a

    Lift a computation from the IO monad. This allows us to run IO computations in any monadic stack, so long as it supports these kinds of operations (i.e. IO is the base monad for the stack).

    Example
    import Control.Monad.Trans.State -- from the "transformers" library
    
    printState :: Show s => StateT s IO ()
    printState = do
      state <- get
      liftIO $ print state

    Had we omitted liftIO, we would have ended up with this error:

    • Couldn't match type ‘IO’ with ‘StateT s IO’
     Expected type: StateT s IO ()
       Actual type: IO ()

    The important part here is the mismatch between StateT s IO () and IO ().

    Luckily, we know of a function that takes an IO a and returns an (m a): liftIO, enabling us to run the program and see the expected results:

    > evalStateT printState "hello"
    "hello"
    
    > evalStateT printState 3
    3
    
Instances33MonadIO, …