packages feed

mockcat-1.5.0.0: README-ja.md

<div align="center">
    <img src="https://raw.githubusercontent.com/pujoheadsoft/mockcat/main/logo.png" width="600px" alt="Mockcat Logo">
    <h1>Stub Haskell functions. Verify calls when needed.</h1>
</div>

<div align="center">

[![Hackage](https://img.shields.io/hackage/v/mockcat.svg)](https://hackage.haskell.org/package/mockcat)
[![Stackage LTS](http://stackage.org/package/mockcat/badge/lts)](http://stackage.org/lts/package/mockcat)
[![Build Status](https://github.com/pujoheadsoft/mockcat/workflows/Test/badge.svg)](https://github.com/pujoheadsoft/mockcat/actions)

[🇺🇸 English](README.md)

</div>

**Mockcat** は、Haskell のためのテストダブルライブラリです。  
スタブ関数 `stub` と、モック関数 `mock` を用意しています。

スタブ関数はこれだけです:
```haskell
-- スタブ: 「"a" が来たら True を返す」
let f :: String -> Bool
    f = stub ("a" ~> True)

f "a"  -- => True
```
`~>` の左に引数、右に戻り値を書くだけ。  
検証は行わず、純粋な関数を返します。

呼び出しの検証が重要な場合は `mock` を使います。  
`expects` を使えば、実行前に期待値を宣言できます:

```haskell
withMockIO $ do
  f <- mock ("a" ~> True)
    `expects` called once   -- 「1回だけ呼ばれるはず」と宣言

  f "a" `shouldBe` True
  -- withMockIO のスコープ終了時に「1回呼ばれたか」がチェックされる
```

> **おすすめの使い方:**
> - 普通の値やラムダ式で十分なら、そのまま使う。
> - 決まった値を返せればよいなら `stub`(純粋、検証なし)。
> - 引数、回数、順序を検証するなら `mock`。

---

## 概念と用語 (Concepts & Terminology)

Mockcat は、決まった値を返すことと、呼び出され方を検証することを分けて扱います。

*   **Stub (スタブ)**:
    期待する引数に対して決まった値を返すことができます。  
    呼び出し履歴を利用した検証が不要な場合に使います。

*   **Mock (モック)**:
    スタブの機能に加え呼び出しの履歴を持ち、「期待通りに呼び出されたか」を検証することができます。  
    検証は実行後に行うことも、実行前に「この条件で呼ばれるはずだ」と宣言することもできます。
---

## Why Mockcat?

純粋なロジックは、値と関数で直接テストできるため、スタブやモックを必要としないでしょう。  
一方で、テストダブルが必要になる場面では、検証のための仕組みを必要とするはずです。  
MockCatは、そういう仕組みを提供するシンプルなライブラリです。

Mockcat は、**特定のアーキテクチャに依存せず、関数の振る舞いと呼び出され方を宣言的に記述できます。**

普通の関数、`IO` を返す関数、引数として注入する関数、Service Handle のフィールド、
MTL / Capability 型クラスなど、既存の設計に合わせて利用できます。

**Mockcat は、テストのために設計を固定するのではなく、設計を試すためにテストを書けることを目指しています。**

### Before / After

Mockcat を使うことで、テストの記述は次のようになります。

| | **Before: 手書き...** 😫 | **After: Mockcat** 🐱✨ |
| :--- | :--- | :--- |
| **定義 (Stub)**<br />「この引数には<br />この値を返したい」 | <pre>f :: String -> IO String<br />f arg = case arg of<br />  "a" -> pure "b"<br />  _   -> error "unexpected"</pre><br />_単純な分岐を書くだけでも行数を消費します。_ | <pre>-- 検証不要なら stub (純粋)<br />let f = stub ("a" ~> "b")</pre><br />_完全な純粋関数として振る舞います。_ |
| **検証 (Verify)**<br />「正しく呼ばれたか<br />テストしたい」 | <pre>-- 記録の仕組みから作る必要がある<br />ref <- newIORef []<br />let f arg = do<br />      modifyIORef ref (arg:)<br />      ...<br /><br />-- 検証ロジック<br />calls <- readIORef ref<br />calls `shouldBe` ["a"]</pre><br />_※ これはよくある一例です。実際にはさらに補助コードが増えがちです。_ | <pre>withMock $ do<br />  -- 定義と同時に期待値を宣言<br />  f <- mock ("a" ~> "b")<br />    &#96;expects&#96; called once<br /><br />  -- 実行するだけ (自動検証)</pre><br />_記録は自動。<br />「何を検証するか」という本質に集中できます。_ |

### 主な特徴

*   **Haskell ネイティブな DSL**: 冗長なデータコンストラクタや専用の記法を覚えなくても、関数定義と同じ感覚 (`引数 ~> 戻り値`) でテストダブルを自然に記述できます。
*   **アーキテクチャ非依存**: MTL (型クラス)、Service Handle (レコード)、あるいは関数。すでにある設計へ Mockcat が合わせます。
*   **値ではなく「条件」で検証**: 引数が `Eq` インスタンスを持っていなくても問題ありません。値の一致だけでなく、「どのような性質を満たすべきか」という条件 (Predicate) で検証できます。
*   **親切なメッセージ**: テスト失敗時、どこが違うのかを「構造差分」で表示します。
    ```text
    function was not called with the expected arguments.

      Closest match:
        expected: Record { name = "Alice", age = 20 }
         but got: Record { name = "Alice", age = 21 }
                                             ^^^
      Specific difference in `age`:
        expected: 20
         but got: 21
                  ^^
    ```
*   **意図を導く型設計**: 型はあなたの記述を縛るものではなく、テストの意図(何を期待しているか)を自然に表現させるために存在します。

---

## クイックスタート

以下のコードをコピペすれば、今すぐ Mockcat を体験できます。

### インストール

`package.yaml`:
```yaml
dependencies:
  - mockcat
```

または `.cabal`:
```cabal
build-depends:
    mockcat
```

### 最初のテスト(検証なし)

```haskell
import Test.Hspec
import Test.MockCat

spec :: Spec
spec = do
  it "stub demo" $ do
    let f :: String -> Int
        f = stub ("Hello" ~> 42)

    f "Hello" `shouldBe` 42
```

### 最初のテスト(検証あり)

```haskell
import Test.Hspec
import Test.MockCat

spec :: Spec
spec = do
  it "mock demo" $ do
    withMockIO $ do
      -- 「1回だけ呼ばれるはず」と期待を宣言
      f <- mock ("Hello" ~> (42 :: Int))
        `expects` called once

      f "Hello" `shouldBe` 42
      -- withMockIO のスコープ終了時に「1回呼ばれたか」がチェックされる
```



## 使い方ガイド (User Guide)

呼び出され方の検証が必要な場合、Mockcat では期待値を書くタイミングに応じて 2 つの検証スタイルを選べます。

### 1. 宣言的な検証 (`withMock` (`withMockIO`) / `expects`)

定義と同時に期待値を記述するスタイルです。  
スコープを抜ける時に自動的に検証が走ります。  
「定義」と「検証」を近くに書きたい場合に便利です。

```haskell
import Test.Hspec
import Test.MockCat
import Control.Monad.IO.Class (MonadIO(liftIO))

spec :: Spec
spec = do
  it "User Guide (withMock)" $ do
    withMock $ do
      -- "Hello" に対して True を返すモックを定義
      f <- mock ("Hello" ~> True)
        `expects` called once -- 一度だけ呼ばれることを期待

      -- 実行
      let result = f "Hello"

      liftIO $ result `shouldBe` True
```

#### `withMockIO`: IO テストの簡略化
`withMockIO` は `withMock` を IO に特化させたバージョンです。  
`liftIO` を使わずにモックコンテキスト内で直接 IO アクションを実行できます。

```haskell
import Test.Hspec
import Test.MockCat

spec :: Spec
spec = do
  it "User Guide (withMockIO)" $ do
    withMockIO $ do
      f <- mock ("Hello" ~> True)
        `expects` called once

      let result = f "Hello"

      result `shouldBe` True
```

> [!IMPORTANT]
> `expects`(宣言的検証)を使用する場合、モック定義部分は必ず **括弧 `(...)`** で囲んでください。
> 以前のバージョンで使用できた `$` 演算子 (`mock $ ... expects ...`) は、優先順位の関係でコンパイルエラーになります。
>
> ❌ `mock $ any ~> True expects ...`
> ✅ `mock (any ~> True) expects ...`

> [!NOTE]
> `runMockT` ブロックの中でも、同様に `expects` を使った宣言的検証が可能です。
> 生成された型クラスのモック関数(`_xxx`)に対してもそのまま使用できます。
>
> ```haskell
> runMockT do
>   _readFile ("config.txt" ~> pure "value")
>     `expects` called once
> ```

### 2. 型クラスを使った設計でのモック (`makeMock`)

型クラスで依存を表現している設計(MTL スタイルや Capability パターン)において、そのままテストに持ち込みたい場合に使います。  
Template Haskell を使って、型クラスからモックを自動生成します。  
これは型クラスを使っている場合の選択肢です。  
テストのためだけに型クラスを導入する必要はありません。

```haskell
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}

class Monad m => FileSystem m where
  readFile :: FilePath -> m String
  writeFile :: FilePath -> String -> m ()

-- [Strict Mode] デフォルトの動作。「mock」関数と挙動が一致します。
-- 戻り値の型が `m a` の場合、スタブ定義の右辺には `m a` 型の値(例: `pure @IO "value"`, `throwIO Error`)を記述する必要があります。
-- Haskell の型システムに対して正直で、明示的な記述を好む場合に推奨されます。
makeMock [t|FileSystem|]

-- [Auto-Lift Mode] 利便性重視のモード。
-- 純粋な値を自動的にモナド(m String など)に包んで返します。
makeAutoLiftMock [t|FileSystem|]
```

> [!NOTE]
> クラスの定義に応じてさらなる言語拡張(`MultiParamTypeClasses` や `UndecidableInstances` など)が必要な場合、Mockcat はコンパイル時に詳細なエラーメッセージを表示して通知します。

テストコード内では `runMockT` ブロックを使用します。

```haskell
spec :: Spec
spec = do
  it "filesystem test" do
    result <- runMockT do
      -- [Strict Mode] (makeMock 使用時): 明示的に pure で包む
      _readFile $ "config.txt" ~> pure @IO "debug=true"
      _writeFile $ "log.txt" ~> "start" ~> pure @IO ()

      -- [Auto-Lift Mode] (makeAutoLiftMock 使用時): 値は自動的に包まれる (便利)
      -- _readFile $ "config.txt" ~> "debug=true"

      -- テスト対象コードの実行(モックが注入される)
      myProgram "config.txt"
    
    result `shouldBe` ()
```

### 3. 関数のモックと事後検証 (`mock` / `shouldBeCalled`)

`mock` を作成してテスト対象を実行した後、記録された呼び出しを `shouldBeCalled` で検証するスタイルです。  
実行後に検証を書く方が自然な場合に使います。

```haskell
import Test.Hspec
import Test.MockCat

spec :: Spec
spec = do
  it "Function Mocking" $ do
    -- "Hello" に対して True を返す関数を定義 (expects は書かない)
    f <- mock ("Hello" ~> True)
    
    -- 実行
    f "Hello" `shouldBe` True

    -- 事後検証 (shouldBeCalled)
    f `shouldBeCalled` "Hello"
```

> [!WARNING]
> **HPC (コードカバレッジ) 環境での制限**
> `stack test --coverage` 等を使用する場合、`shouldBeCalled` は使用しないでください。
> GHC のカバレッジ計測機能が関数をラップするため、関数の同一性が失われ、検証に失敗します。
> カバレッジ計測が必要な場合は、**`expects`** スタイル (Section 1) を使用してください。

**柔軟なマッチング**:
具体的な値だけでなく、条件(述語)を指定することもできます。

```haskell
{-# LANGUAGE TypeApplications #-}
import Test.Hspec
import Test.MockCat
import Prelude hiding (any)

spec :: Spec
spec = do
  it "Matcher Examples" $ do
    -- 任意の文字列 (param any)
    f <- mock (any @String ~> True)
    f "foo" `shouldBe` True

    -- 条件式 (when)
    g <- mock (when (> (5 :: Int)) "> 5" ~> True)
    g 6 `shouldBe` True
```

### 4. 柔軟な検証(マッチャー)

引数が `Eq` インスタンスを持っていなくても、あるいは特定の値に依存したくない場合でも、「どのような条件を満たすべきか」という**意図**で検証できます。  
Mockcat は、値の一致だけでなく、関数の性質を検証するための**マッチャー**を提供しています。

#### 任意の値を許可 (`any`)

```haskell
-- どんな引数で呼ばれても True を返す
f <- mock (any @String ~> True)

-- 何でもいいから呼ばれたことを検証
f `shouldBeCalled` any
```

#### 条件を指定して検証 (`when`)

任意の値ではなく、「条件(述語)」を使って検証できます。  
`Eq` を持たない型(関数など)や、部分的な一致を確認したい場合に強力です。

```haskell
it "When Example" $ do
  -- 引数が "error" で始まる場合のみ False を返す
  f <- mock $ do
    onCase $ when (\s -> "error" `isPrefixOf` s) "start with error" ~> False
    onCase $ any ~> True

  f "error message" `shouldBe` False
  f "success" `shouldBe` True
  f "other" `shouldBe` True
```

ラベル(エラー時に表示される説明)が不要な場合は、`when_` を使用することもできます。

```haskell
f <- mock (when_ (> (5 :: Int)) ~> True)
```

### 5. 高度な機能 - [応用]

#### mock vs stub vs mockM の使い分け

まず呼び出しの検証が必要かを判断します。  
普通の値や関数で十分ならそのまま使い、決まった応答だけが必要なら `stub` を使います。  
呼び出され方自体を検証する場合に `mock` または `mockM` を選びます。

| 関数 | 検証 (`shouldBeCalled`) | IO 依存 | 特徴 |
| :--- | :---: | :---: | :--- |
| **`stub`** | ❌ | なし | **純粋なスタブ**。IO に依存しません。検証不要ならこれで十分です。 |
| **`mock`** | ✅ | なし(外部管理) | **モック**。純粋関数として振る舞い、履歴を自動的に記録します。 |
| **`mockM`** | ✅ | あり(明示) | **Monadic モック**。`MockT` や `IO` の中で使い、副作用(ロギングなど)を明示的に扱えます。 |

#### mock と mockM の使い分け

呼び出され方の検証が必要だと判断した後、対象となる関数の**戻り値の型**に合わせて選択してください。

*   **`mock` (純粋な関数向け)**:
    *   `String -> Int` のような**純粋な関数**をモックする場合に使用します。
    *   Haskell の遅延評価を尊重し、「実際に結果が評価されたタイミング」で呼び出しを記録します。これにより、使われていない無駄な呼び出しをカウントしてしまうのを防ぎます。

> [!IMPORTANT]
> `mock` は純粋な関数 (`a -> b`) として振る舞うため、
> **GHC の最適化(CSE / CAF 化 / full laziness)の影響を受けます**。
>
> その結果、ソースコード上では複数回書かれていても、
> コンパイル後のプログラムでは **1回しか評価されない** 場合があります。
>
> Mockcat は「ソース上の記述回数」ではなく、
> **実際に評価された回数**を記録・検証します。


*   **`mockM` (IO/モナディックな関数向け)**:
    *   `String -> IO Int` のような、**`IO` や `ReaderT IO` などの `MonadIO` インスタンスを返す関数**をモックする場合に使用します。
    *   記録処理が戻り値のアクション(`IO`)自体に組み込まれているため、高度な並列テストや強力な最適化がかかる環境下でも、非常に高い予測可能性を提供します。

> [!TIP]
> 呼び出され方の検証が必要だと判断した後は、**「ターゲットの関数が IO を返すなら `mockM`、そうでないなら `mock`」** と覚えておけば間違いありません。

#### 部分モック (Partial Mock): 本物の関数と混ぜて使う

一部のメソッドだけモックに差し替え、残りは本物の実装を使いたい場合に便利です。

```haskell
-- [Strict Mode]
makePartialMock [t|FileSystem|]

-- [Auto-Lift Mode]
-- makeAutoLiftMock と同様に、Partial Mock にも Auto-Lift 版があります。
makeAutoLiftPartialMock [t|FileSystem|]

instance FileSystem IO where ... -- 本物のインスタンスも必要

test = runMockT do
  _readFile $ "test" ~> pure @IO "content" -- readFile だけモック化 (Strict)
  -- or
  -- _readFile $ "test" ~> "content" -- (Auto-Lift)

  program -- writeFile は本物の IO インスタンスが走る
```

#### 派生とカスタムインスタンス (Derivation and Custom Instances)

`MockT` を使用する際、モック対象の副作用とは直接関係のない型クラスを扱わなければならないことがあります。  
Mockcat は、これらのケースを補助するためのマクロを提供しています。

##### MTL インスタンス (`MonadReader`, `MonadError` 等)
`MockT` は、標準的な `mtl` の型クラス(`MonadReader`, `MonadError`, `MonadState`, `MonadWriter`)のインスタンスを標準で備えています。  
これらのインスタンスは、操作を自動的にベースモナドへリフト(持ち上げ)します。

##### カスタム型クラスの派生 (`deriveMockInstances`)
ベースモナドへリフトするだけでよいカスタムの "Capability" 型クラス(`MonadLogger`, `MonadConfig` 等)については、`deriveMockInstances` を使用できます。

```haskell
class Monad m => MonadLogger m where
  logInfo :: String -> m ()

deriveMockInstances [t|MonadLogger|]
```
これにより、`lift . logInfo` を呼び出す `MockT m` のインスタンスが自動生成されます。

##### 明示的な No-op インスタンス (`deriveNoopInstance`)
メソッド(特に `m ()` を返すもの)に対して、明示的なスタブ定義やベース実装を用意することなく、「何もしない」モックを作成したい場合があります。

```haskell
class Monad m => MonadAuditor m where
  audit :: String -> m ()

deriveNoopInstance [t|MonadAuditor|]
```
これにより、`audit` が単に `pure ()` を返す `MockT m` のインスタンスが生成されます。


---

#### 逐次応答

case は Haskell のパターンマッチと同様に上から順に照合され、最初に一致したcase だけが選ばれます。  
各 case は独立した応答列を持ち、その case を選んだ呼び出しだけが列を進めます。  
末尾へ到達した後は最後の応答を返し続けます。

つまり、入力による分岐を `onCase` で記述し、選ばれた case の呼び出しに伴う時間的な変化を `andThen` で記述します。

```haskell
f <- mock do
  onCase $ "A" ~> 1
    `andThen` 2
    `andThen` 3
  onCase $ any @String ~> 9
    `andThen` 10
    `andThen` 11

-- 呼び出し: A, B, A, C, A, B, A, C
-- 結果:     1, 9, 2, 10, 3, 11, 3, 11
```

後ろにある重複caseには到達しません。  
同じ条件で値を順番に返す場合は、一つのcaseへ `andThen` で応答を追加してください。

#### IO アクションを返す (Monadic Return)

`IO`を返す関数で呼び出しごとに副作用や結果を変える場合にも、`andThen` を利用できます。

```haskell
f <- mock do
  onCase $ "get" ~> pure @IO 1 -- 1回目
    `andThen` pure @IO 2        -- 2回目以降
```

#### 名前付きモック

エラーメッセージに関数名を表示させたい場合は、ラベルを付けられます。

```haskell
f <- mock (label "myAPI") ("arg" ~> True)
```

---

## リファレンス & レシピ (Encyclopedia)

※ このセクションは、困ったときの辞書として使ってください。

### 宣言的検証 DSL (`expects`)

`expects` ブロックでは、ビルダースタイルの構文を使って宣言的に期待値を記述できます。  
`shouldBeCalled` と共通の語彙を使用しています。

#### 基本的な使い方

`called` で開始し、条件を連鎖させて記述します。

```haskell
-- 回数のみ
mock (any ~> True) `expects` called once

-- 引数を指定
mock (any ~> True) `expects` (called once `with` "arg")

-- 複数の期待値 (do ブロック)
mock (any ~> True) `expects` do
  called once `with` "A"
  called once `with` "B"
```

#### 構文リファレンス

| Builder | 説明 | 例 |
| :--- | :--- | :--- |
| **`called`** | **[必須]** 期待値ビルダーを開始します。 | `called ...` |
| **`times n`** | 回数を指定します。 | `called . times 2` |
| **`once`** | `times 1` のエイリアス。 | `called . once` |
| **`never`** | 0回を期待します。 | `called . never` |
| **`with arg`** | 引数を指定します。 | `called `with` "value"` |
| **`with matcher`** | マッチャを使って引数を検証します。 | `called `with` when (>5) "gt 5"` |
| **`inOrder`** | 呼び出し順序を検証 (リスト内で使用) | (順序検証の項を参照) |

### 検証マッチャ一覧 (`shouldBeCalled`)

| マッチャ | 説明 | 例 |
| :--- | :--- | :--- |
| `x` (値そのもの) | その値で呼ばれたか | ``f `shouldBeCalled` (10 :: Int)`` |
| `times n` | 回数指定 | ``f `shouldBeCalled` (times 3 `with` "arg")`` |
| `once` | 1回だけ | ``f `shouldBeCalled` (once `with` "arg")`` |
| `never` | 呼ばれていない | ``f `shouldBeCalled` never`` |
| `atLeast n` | n回以上 | ``f `shouldBeCalled` atLeast 2`` |
| `atMost n` | n回以下 | ``f `shouldBeCalled` atMost 5`` |
| `anything` | 引数は何でも良い(回数不問) | ``f `shouldBeCalled` anything`` |
| `inOrderWith [...]` | 厳密な順序 | ``f `shouldBeCalled` inOrderWith ["a", "b"]`` |
| `inPartialOrderWith [...]` | 部分的順序(間飛びOK) | ``f `shouldBeCalled` inPartialOrderWith ["a", "c"]`` |

### パラメータマッチャ一覧(引数定義)

| マッチャ | 説明 | 例 |
| :--- | :--- | :--- |
| `any` | 任意の値 | `any ~> True` |
| `when pred label` | 条件式 | `when (>0) "positive" ~> True` |
| `when_ pred` | ラベルなし | `when_ (>0) ~> True` |

### よくある質問 (FAQ)

<details>
<summary><strong>Q. 未評価の遅延評価はどう扱われますか?</strong></summary>
A. カウントされません。Mockcat は「結果が評価された時点」で呼び出しを記録します (Honest Laziness)。これにより、不要な計算による誤検知を防ぎます。
</details>

<details>
<summary><strong>Q. 並列テストで使えますか?</strong></summary>
A. はい。内部で `TVar` を使用してアトミックにカウントしているため、`mapConcurrently` などで並列に呼ばれても正確に記録されます。
</details>

<details>
<summary><strong>Q. コードカバレッジ (HPC) を有効にしてテストを実行できますか?</strong></summary>
A. はい (v1.1.0.0 以降)。Mockcat の `expects` スタイルは、HPC による関数のラップの影響を受けない設計になっているため、HPC下でも安全に動作します。
ただし、前述の理由により **`expects`** スタイル (または `withMock`) の使用を推奨します。
`shouldBeCalled` スタイルは、HPC の仕組み上、モックの同一性を特定できないため使用できません。
</details>

<details>
<summary><strong>Q. `makeMock` が生成するコードは何ですか?</strong></summary>
A. 指定された型クラスの `MockT m` インスタンスと、各メソッドに対応する `_メソッド名` というスタブ生成関数定義です。
</details>

<details>
<summary><strong>Q. 厳密な定義では Spy ではないですか?</strong></summary>
A. はい、xUnit Patterns 等の定義に従えば、事後検証を行う Mockcat のモックは **Test Spy** に分類されます。<br>
しかし、近年の多くのライブラリ(Jest, Mockito 等)がこれらを包括して「モック」と呼称していること、および用語の乱立による混乱を避けるため、本ライブラリでは **"Mock"** という用語で統一しています。
</details>

<details>
<summary><strong>Q. テストで呼び出し回数が期待より少なくカウントされることがあります</strong></summary>

A. `mock` は純粋関数として扱われるため、GHC の最適化により評価が共有される場合があります。
これは Mockcat の仕様であり、コンパイル後の実行結果を正確に反映した挙動です。

Mockcat はランタイムにおける **「実際の評価回数」** を記録します。
そのため、最適化によって同一の式が共有された場合は、事実通り「1回」とカウントされます。

テスト目的で評価の共有を抑制したい場合は、テストファイルに以下の
**GHC プラグマ**を指定することもできます。

```haskell
{-# OPTIONS_GHC -fno-cse #-}
{-# OPTIONS_GHC -fno-full-laziness #-}
```

これは **テスト専用の設定** で、ソースコード上の呼び出し回数に近い挙動を確認したい場合に便利です。
</details>

## 実践的な例

Mockcat はプロダクションコードの設計を規定しません。  
純粋なコードには普通の値や関数を使い、小さく直接的なテストダブルが役立つ境界にだけ Mockcat を導入します。

以下は mockcat を使った実践的なテストスイートです:

- **MTL + Capability パターン**: Port ベースのアプリケーションテスト(`MockT` / `ExceptT` を使用)
  👉 [UsecaseSpec.hs (cli-mtl)](https://github.com/pujoheadsoft/haskell-layered-examples/blob/main/cli-mtl/test/Application/UsecaseSpec.hs)

- **Polysemy エフェクト**: stub でデータを流し、mock で検証が必要な箇所だけを検証
  👉 [UsecaseSpec.hs (cli-effect-polysemy)](https://github.com/pujoheadsoft/haskell-layered-examples/blob/main/cli-effect-polysemy/test/Application/UsecaseSpec.hs)

## ヒントとトラブルシューティング

### `any` と `Prelude.any` の名前衝突
`Test.MockCat` をインポートすると、パラメータマッチャの `any` が `Prelude.any` と衝突することがあります。  
その場合は `Prelude` の `any` を隠すか、修飾名を使用してください。

```haskell
import Prelude hiding (any)
-- または
import qualified Test.MockCat as MC
```

### `when` と `Control.Monad.when` の名前衝突
`Test.MockCat` は `when` (パラメータマッチャ) をエクスポートするため、`Control.Monad` の `when` (条件分岐) と衝突することがあります。  
その場合は `Test.MockCat` からの `when` を隠すか、修飾名を使用してください。

```haskell
import Test.MockCat hiding (when)
-- または
import Control.Monad hiding (when) -- モックの方を使いたい場合
```

### `OverloadedStrings` 使用時の型推論エラー
`OverloadedStrings` 拡張を有効にしている場合、文字列リテラルの型が曖昧になり、エラーが発生することがあります。
その場合は明示的に型注釈を付けてください。

```haskell
mock (("value" :: String) ~> True)
```

---

_Happy Mocking!_ 🐱