assert4hs-core: A set of assertion for writing more readable tests cases

[ library, mit, testing ] [ Propose Tags ]

Please see the README on GitHub at https://github.com/paweln1986/assert4hs#readme


[Skip to Readme]
Versions [RSS] [faq] 0.1.0
Change log ChangeLog.md
Dependencies base (>=4.7 && <5), data-default (>=0.7.1.1), pretty-diff (>=0.4.0.0), text (>=1.2.4.1) [details]
License MIT
Copyright 2021 Pawel Nosal
Author Pawel Nosal
Maintainer p.nosal1986@gmail.com
Category Testing
Home page https://github.com/paweln1986/assert4hs-core#readme
Bug tracker https://github.com/paweln1986/assert4hs-core/issues
Source repo head: git clone https://github.com/paweln1986/assert4hs-core
Uploaded by paweln1986 at 2021-04-08T18:26:50Z
Distributions NixOS:0.1.0
Downloads 84 total (9 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Hackage Matrix CI
Docs available [build log]
Last success reported on 2021-04-08 [all 1 reports]

Modules

[Index] [Quick Jump]

Downloads

Maintainer's Corner

For package maintainers and hackage trustees

Candidates


Readme for assert4hs-core-0.1.0

[back to package description]

assert4hs

This library aims to provide a set of combinators to assert arbitrary nested data structures. The inspiration of this library is AssertJ for Java, the composition of assertions was inspired by lens library.

New assertions can be easily written and composed with other assertions. All failed assertions are gathered and presented to the user.

  data Foo = Foo {name :: String, age :: Int} deriving (Show, Eq)

  assertThat (Foo "someName" 15) $
       isEqualTo (Foo "someN1ame" 15)
       . focus age
       . tag "age"
       . isGreaterThan 20

result in

  given Foo {name = "someName", age = 15} should be equal to Foo {name = "someN1ame", age = 15}
  Foo {name = "someName", age = 15}
  ╷
  │
  ╵
  Foo {name = "someN1ame", age = 15}
                    ▲
  [age] given 15 should be greater than 20

Examples

Simple assertion
  result = 10
  assertThat result $ isEqual 10
Composing assertion

Assertions are composable, this allows verifying multiple conditions during one test case.

  result = 10
  assertThat result $ 
      isGreaterThan 5 
      . isLowerThan 20
 
 
 >>> given 4 should be greater than 5
Focusing on part of data structure

Sometimes it is convenient to transform the subject under test and execute assertions on the extracted part of it. For this purpose, we have a focus function.

  data Foo = Foo {name :: String, age :: Int} deriving (Show, Eq)

  assertThat (Foo "someName" 15) $
      isEqualTo (Foo "someName" 15)
      . focus age
      . isGreaterThan 20
      . isLowerEqualThan 5

  >>> given 15 should be greater than 20 
  >>> given 15 should be lower or equal to 5
Changing subject uder test

The focus function allows to transform the subject under test, but the original subject is lost. Function inside is similar to the function focus, but preserve theoriginal subject under test.

data Foo = Foo {name :: String, age :: Int} deriving (Show, Eq)

assertThat (Foo "someName" 15) $
    inside age (isGreaterThan 20 . isLowerEqualThan 5)
    . focus name 
    . isEqualTo "someName1" 

>>> given 15 should be greater than 20
>>> 
>>> given 15 should be lower or equal to 5
>>> 
>>> given "someName" should be equal to "someName1"
>>> "someName"
>>> ╷
>>> │
>>> ╵
>>> "someName1"
>>>          ▲
Tagging assertions

Once our test grows, it is hard to spot which assertions failed and why. That is why function tag exists, one can name assertion and give it a more readable name for failure message.


data Foo = Foo {name :: String, age :: Int} deriving (Show, Eq)

assertThat (Foo "someName" 15) $
  inside age (tag "age" . isGreaterThan 20 . isLowerEqualThan 5)
    . tag "name"
    . focus name
    . isEqualTo "someName1"
    . tag "should not be equal"
    . isNotEqualTo "someName"

>>> [age] given 15 should be greater than 20
>>> 
>>> [age] given 15 should be lower or equal to 5
>>> 
>>> [name] given "someName" should be equal to "someName1"
>>> "someName"
>>> ╷
>>> │
>>> ╵
>>> "someName1"
>>>          ▲
>>> 
>>> [name.should not be equal] given "someName" should be not equal to "someName"
Custom assertions

It is sometimes convenient to create a custom assertion which explicitly describes what is testing. For this purpose we have simpleAssertion function

isSuitableForEmployment :: Assertion Foo
isSuitableForEmployment =
    simpleAssertion (\a -> age a > 17) (\a -> "new employee must be 18 years or older, but it has " <> show (age a))
    . simpleAssertion (\a -> age a < 70) (\a -> "must be younger than 70 years old, but it has " <> show (age a))

assertThat (Foo "someName" 15) isSuitableForEmployment

>>> new employee must be 18 years or older, but it has 15

assertThat (Foo "someName" 76) isSuitableForEmployment

>>> must be younger than 70 years old, but it has 76

assert4hs-hspec - integration point of assert4hs and hspec

assert4hs-tasty - integration point of assert4hs and tasty