mockcat-0.1.0.0: README.md
# 🐈Mocking library for Haskell🐈
[](https://github.com/pujoheadsoft/mockcat/actions?query=workflow%3ATest+branch%3Amain)
[日本語版 README はこちら](https://github.com/pujoheadsoft/mockcat/blob/master/README-ja.md)
mockcat is a simple mocking library that supports testing in Haskell.
It mainly provides two features:
- Creating stub functions
- Verifying if the expected arguments were applied
Stub functions can return not only monadic values but also pure values.
```haskell
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE TypeApplications #-}
import Test.Hspec
import Test.MockCat
spec :: Spec
spec = do
it "Example of usage" do
-- Create a Mock (applying “value” returns the pure value True)
mock <- createMock $ "value" |> True
-- Extract the stub function from the mock
let stubFunction = stubFn mock
-- Verify the results of applying an argument
stubFunction "value" `shouldBe` True
-- Verify if the expected value ("value") was applied
mock `shouldApplyTo` "value"
```
# Stub Functions
## Simple Stub Functions
To create stub functions, use the createStubFn function.
```haskell
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE TypeApplications #-}
import Test.Hspec
import Test.MockCat
spec :: Spec
spec = do
it "can create a stub function" do
-- Create
f <- createStubFn $ "param1" |> "param2" |> pure @IO ()
-- Apply
actual <- f "param1" "param2"
-- Verify
actual `shouldBe` ()
```
To createStubFn, you pass the expected arguments concatenated with |>.
The final value after |> is the return value of the function.
If unexpected arguments are applied to the stub function, an error occurs.
```console
uncaught exception: ErrorCall
Expected arguments were not applied to the function.
expected: "value"
but got: "valuo"
```
## Named Stub Functions
You can name stub functions.
```haskell
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE TypeApplications #-}
import Test.Hspec
import Test.MockCat
spec :: Spec
spec = do
it "named stub" do
f <- createNamedStubFun "named stub" $ "x" |> "y" |> True
f "x" "z" `shouldBe` True
```
If the expected arguments are not applied, the error message will include this name.
```console
uncaught exception: ErrorCall
Expected arguments were not applied to the function `named stub`.
expected: "x","y"
but got: "x","z"
```
## Flexible Stub Functions
You can create a flexible stub function by giving the `createStubFn` function a conditional expression instead of a specific value.
This allows you to return expected values for arbitrary values, strings matching specific patterns, etc.
### any
any matches any value.
```haskell
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE TypeApplications #-}
import Test.Hspec
import Test.MockCat
import Prelude hiding (any)
spec :: Spec
spec = do
it "any" do
f <- createStubFn $ any |> "return value"
f "something" `shouldBe` "return value"
```
Since a function with the same name is defined in Prelude, we use import Prelude hiding (any).
### Condition Expressions
Using the expect function, you can handle arbitrary condition expressions.
The expect function takes a condition expression and a label.
The label is used in the error message if the condition is not met.
```haskell
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE TypeApplications #-}
import Test.Hspec
import Test.MockCat
spec :: Spec
spec = do
it "expect" do
f <- createStubFn $ expect (> 5) "> 5" |> "return value"
f 6 `shouldBe` "return value"
```
### Condition Expressions without Labels
`expect_` is a label-free version of expect.
The error message will show [some condition].
```haskell
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE TypeApplications #-}
import Test.Hspec
import Test.MockCat
spec :: Spec
spec = do
it "expect_" do
f <- createStubFn $ expect_ (> 5) |> "return value"
f 6 `shouldBe` "return value"
```
### Condition Expressions using Template Haskell
Using expectByExp, you can handle condition expressions as values of type Q Exp.
The error message will include the string representation of the condition expression.
```haskell
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TemplateHaskell #-}
import Test.Hspec
import Test.MockCat
spec :: Spec
spec = do
it "expectByExpr" do
f <- createStubFn $ $(expectByExpr [|(> 5)|]) |> "return value"
f 6 `shouldBe` "return value"
```
## Stub Functions that Return Different Values for Each Applied Argument
By applying a list in the form of x |> y to the `createStubFn` function,
you can create stub functions that return different values for each applied argument.
```haskell
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE TypeApplications #-}
import Test.Hspec
import Test.MockCat
import Prelude hiding (and)
spec :: Spec
spec = do
it "multi" do
f <-
createStubFn
[ "a" |> "return x",
"b" |> "return y"
]
f "a" `shouldBe` "return x"
f "b" `shouldBe` "return y"
```
# Verification
## Verify if the Expected Arguments were Applied
You can verify if the expected arguments were applied using the `shouldApplyTo` function.
To perform the verification, create a mock using the `createMock` function instead of the `createStubFn` function.
In this case, use the `stubFn` function to extract the stub function from the mock.
```haskell
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE TypeApplications #-}
import Test.Hspec
import Test.MockCat
spec :: Spec
spec = do
it "stub & verify" do
-- create a mock
mock <- createMock $ "value" |> True
-- stub function
let stubFunction = stubFn mock
-- assert
stubFunction "value" `shouldBe` True
-- verify
mock `shouldApplyTo` "value"
```
## Verify the Number of Times the Expected Arguments were Applied
You can verify the number of times the expected arguments were applied using the `shouldApplyTimes` function.
```haskell
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE TypeApplications #-}
import Test.Hspec
import Test.MockCat
spec :: Spec
spec = do
it "shouldApplyTimes" do
m <- createMock $ "value" |> True
print $ stubFn m "value"
print $ stubFn m "value"
m `shouldApplyTimes` (2 :: Int) `to` "value"
```
## Verify if the Arguments were Applied in the Expected Order
You can verify if the arguments were applied in the expected order using the `shouldApplyInOrder` function.
```haskell
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE TypeApplications #-}
import Test.Hspec
import Test.MockCat
spec :: Spec
spec = do
it "shouldApplyInOrder" do
m <- createMock $ any |> True |> ()
print $ stubFn m "a" True
print $ stubFn m "b" True
m
`shouldApplyInOrder` [ "a" |> True,
"b" |> True
]
```
## Verify if the Arguments were Applied in the Expected Partial Order
The `shouldApplyInOrder` function strictly verifies the order of application,
but the `shouldApplyInPartialOrder` function can verify if the order of application matches partially.
```haskell
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE TypeApplications #-}
import Test.Hspec
import Test.MockCat
spec :: Spec
spec = do
it "shouldApplyInPartialOrder" do
m <- createMock $ any |> True |> ()
print $ stubFn m "a" True
print $ stubFn m "b" True
print $ stubFn m "c" True
m
`shouldApplyInPartialOrder` [ "a" |> True,
"c" |> True
]
```