テスト

モックとは?スタブとの違い・テストダブル5分類と単体テストでの使い分けを実装者向けに解説

モックとは、単体テストで本物の依存オブジェクトの代わりに置く「振る舞いを検証するための代用品」です。同じ代用品でも、決まった戻り値を返すだけのスタブとは目的が異なり、ここを混同するとテストが壊れやすくなるのが落とし穴です。この記事では、モックとスタブを「状態検証/振る舞い検証」という軸で切り分け、テストダブルの5分類(ダミー・スタブ・スパイ・モック・フェイク)の位置づけ、Mockito・unittest.mock・Jestなど言語別ライブラリの実装差、そして過剰モック(モック地獄)に陥る兆候と是正までを、実装者がテストコードを書く視点で整理します。テスト全体の配分設計はテストピラミッドの関連記事に接続します。

目次

まとめ:モックは「振る舞い」を検証し、スタブは「状態」を用意する道具

先に結論を示します。モックとスタブはどちらもテスト対象の依存を置き換えるテストダブルですが、使う目的が正反対です。スタブはテスト対象に決まった入力(戻り値)を用意するための道具で、検証の主役はテスト対象が返す「状態」です。モックは依存が正しく呼ばれたか(回数・引数・順序)という「相互作用」を検証するための道具で、モック自身が期待どおりに呼ばれたかを判定します。

実装者が押さえる判断は2つに絞れます。第一に、テストで確かめたいのが「戻り値や最終状態」ならスタブ、「依存を正しく操作したか」ならモックを選ぶ。第二に、モックは実装の内部手順に密着しやすいため、増やしすぎると仕様変更のたびにテストが赤くなる負債に変わります。メール送信やDB書き込みのように副作用そのものを確かめたいときだけモックを使い、それ以外は戻り値を差し替えるスタブで足りる——この線引きが、モックを扱ううえでの芯です。

モックの定義と、テストダブル5分類の中でのモックの位置づけと役割

まず「モックとは何か」を、テストダブルという上位概念の中で位置づけます。呼び名が乱れやすい領域なので、分類の地図を先に持つと迷いません。

モックとは何か——依存を置き換える代用品と、単体テストで使う理由

モックは、テスト対象が依存する外部コンポーネント(他クラス・DB・外部API・時刻・乱数など)を、テスト時だけ差し替える偽物のオブジェクトです。目的は、テスト対象のロジックを外部要因から切り離して、狭く速く検証できるようにすることにあります。本物のDBや外部APIを呼ぶと、テストは遅く、ネットワークやデータ状態に左右されて壊れやすくなります。

モックが単体テストで使われる直接の理由は、この「切り離し」です。たとえば「在庫がゼロなら発注メールを送る」ロジックを検証したいとき、実際にメールを飛ばすわけにはいきません。メール送信クライアントをモックに差し替え、send()が正しい宛先で1回だけ呼ばれたかを検証すれば、副作用を起こさずロジックの正しさだけを確かめられます。この「呼ばれ方を検証する」性格が、次に述べるスタブとの決定的な違いです。

テストダブル5分類(Dummy/Stub/Spy/Mock/Fake)の役割と境界

「モック」は本来、より広いテストダブルという総称の一員です。Gerard Meszaros氏が著書『xUnit Test Patterns』(2007年)で整理した5分類が、いまも共通言語として使われています。5つは検証の関与度が浅い順に並べると理解しやすくなります。

種類 役割 戻り値 呼び出しの検証
ダミー(Dummy) 引数の数合わせに渡すだけで使われない なし しない
スタブ(Stub) 決まった値を返しテスト対象に入力を与える 固定で返す しない
スパイ(Spy) スタブに加え呼び出し内容を記録し後で確認 返せる テスト後に検証
モック(Mock) 期待する呼ばれ方を事前に設定し満たすか判定 返せる 期待違反で即失敗
フェイク(Fake) 簡易実装で本物同様に動く(インメモリDB等) 実際に動作 しない

境界を一言でいうと、戻り値だけ欲しいならスタブ、呼ばれ方まで確かめたいならモックかスパイ、本物に近い挙動が要るならフェイクです。5つを厳密に呼び分けられる必要はありませんが、少なくとも「入力を与える道具(スタブ)」と「相互作用を検証する道具(モック)」は分けて考えると、テストの意図がコードに表れます。

モックとスタブの違いを、状態検証と振る舞い検証の2軸で切り分ける

実務でいちばん問われるのが「モックとスタブの違い」です。この差は、Martin Fowler氏が2007年の記事「Mocks Aren’t Stubs」で示した2つの検証スタイルで整理すると明快になります。

スタブは状態検証、モックは振る舞い検証という使い分けの判断軸

スタブは「状態検証(state verification)」に使います。依存が返す値を固定しておき、その入力を受けたテスト対象が最終的にどんな戻り値や状態になったかを確かめる形です。検証の対象はあくまでテスト対象であり、スタブ自身がどう呼ばれたかは問いません。割引計算のテストで、料金マスタから固定価格を返すスタブを置き、計算結果の金額だけをアサートするのが典型です。

モックは「振る舞い検証(behavior verification)」に使います。依存オブジェクトが期待どおりに操作されたか——どのメソッドが、何回、どんな引数で呼ばれたか——をモック自身が判定します。戻り値では確認できない副作用(通知の送信、ログの記録、外部システムへの登録)が正しく発火したかを保証したいときに向く道具です。Fowler氏はスタブ中心の設計を古典派(Classical)、モック中心の設計をモック派(Mockist)と呼び、両者はテスト設計の思想の違いだと整理しました。

スパイ・フェイクとの違いと、実務で呼び名が曖昧になりやすい理由

現場では、これらを総称して何でも「モック」と呼ぶ傾向があります。曖昧さの主因は、Mockitoに代表される多くのライブラリが、スタブ・モック・スパイの機能を1つのAPIで提供している点にあります。when(...).thenReturn(...)はスタブ的な設定、verify(...)はモック的な検証で、同じオブジェクトが文脈で役割を変えるので、名前の境界は実装上ぼやけがちです。

フェイクだけは性格が明確に異なります。スタブやモックが「呼ばれたら決めた値を返す・記録する」だけの浅い偽物なのに対し、フェイクはインメモリのデータベースや簡易的なリポジトリ実装のように、本物に近い動作ロジックを内部に持ちます。テストのために本物のDBを立てたくないが、複数回の読み書きが整合する挙動は欲しい、という場面で選ばれる道具です。呼び分けに迷ったら、「値を返すだけ=スタブ、呼ばれ方を検証=モック、動く簡易実装=フェイク」と役割で判断すれば実務上は困りません。

言語別モックライブラリ(Mockito/unittest.mock/Jest)の実装差

モックの考え方は言語共通ですが、標準的に使われるライブラリと書き味は環境ごとに異なります。代表的なものを整理します。

言語/環境 主なライブラリ スタブ設定の例 検証の例
Java Mockito when().thenReturn() verify().save()
Python unittest.mock(標準) return_value= assert_called_once
JavaScript Jest mockReturnValue() toHaveBeenCalled()

Pythonのunittest.mockはPython 3.3以降で標準ライブラリに含まれ、追加インストールなしで使えます。JavaではMockitoが事実上の標準で、5系(2026年7月時点)が広く使われています。JavaScriptはJestjest.fn()jest.mock()でモック関数を生成する仕組みです。いずれもスタブ(戻り値の設定)とモック(呼び出しの検証)を同一APIで扱う設計であり、前述の「呼び名が曖昧になる」構造はライブラリの作りに由来します。

モックを使う場面・使わない場面と、過剰モックに陥る失敗パターン

ここからは判断を言い切ります。モックは便利な道具ですが万能ではありません。増やすほどテストが実装に密着して脆くなる副作用があるためです。使いどころと崩れる兆候を整理します。

モックが有効な場面と、実物・フェイクで代替すべき場面の判断基準

モックが効くのは、依存の「呼ばれ方そのもの」が仕様になっている場面です。外部システムへの通知送信、決済APIの呼び出し、イベントの発行など、副作用が正しく起きたことを保証したいケースでは、モックの振る舞い検証が素直に効きます。逆に、テストで確かめたいのが最終的な戻り値や状態なら、スタブで入力を用意するだけで足り、モックにする必要はありません。

一方で、モックにすべきでない場面もはっきりしています。自分が書いた値オブジェクトや純粋なロジック(副作用のない計算・分岐)はモックせず、本物のまま呼ぶべきです。また、複数回の読み書きの整合を確かめたいリポジトリは、モックで戻り値を積むよりインメモリのフェイクに置き換えたほうが、テストが実装手順に縛られません。判断の目安は「その依存の呼ばれ方は、変えてはいけない仕様か」。仕様ならモック、単なる入力源ならスタブかフェイク、という順で選びます。

過剰モック(いわゆるモック地獄)に陥る失敗パターンと是正の手順

最も避けたい失敗が、あらゆる依存を無条件にモック化する過剰モックです。テストの見た目は緑でも、内部実装の手順(どのメソッドをどの順で呼ぶか)に密着するため、リファクタリングで振る舞いが同じでもテストが赤くなります。兆候ははっきりしています。1つのテストのモック設定が10行を超える、privateメソッドの呼び出し回数まで検証している、実装を変えていないのに大量のテストが壊れる——どれかが出たら過剰モックを疑うべきです。

是正は「モックを実物・フェイクへ降ろす」方向で進めます。副作用のない依存はモックを外して本物を呼び、DB系はインメモリのフェイクへ置き換え、モックの検証は「変わってはいけない副作用」だけに絞る。モックを減らすとテストは実装から独立し、回帰時に壊れにくくなります。どの範囲を作り直し、どこを自動テストで守り続けるかの線引きは、リグレッションテストの範囲選定と自動化の考え方と併せて設計すると、モック削減の効果が回帰の効率にも直結します。

テストピラミッドの層別配分の中でモックをどこに位置づけるべきか

モックは単体テストを厚くするための道具であり、テスト全体の配分設計と切り離せません。テストピラミッドでは、速く壊れにくい単体テストを土台に厚く積みます。この土台を厚くできるのは、依存をモックやスタブで差し替えて外部要因から切り離せるからです。逆にいえば、モックで切り離せない密結合なコードは、単体テストにできず結合テストやE2Eへ押し上げられ、ピラミッドを崩す要因になります。配分設計の全体像はテストピラミッドの層別配分と実装者向けのテスト戦略設計で扱っています。

注意したいのは、モックで単体層を厚くしすぎると、今度は「本物同士のつなぎ目」が誰も検証しない死角になる点です。モックはあくまで単体層の道具で、実際の連携はE2Eや結合テストが受け持ちます。モックが増えたぶんだけ、収益に直結する主要導線だけを実物で通すE2Eテストの目的と範囲の絞り込みで下支えする、という役割分担が要ります。テスト工程全体の設計思想はシステム開発におけるテスト工程の全体像を判断ハブとして参照してください。

モックを含むテスト戦略を内製で定着させる設計と、外部支援の使いどころ

モックの使い分けは、一度ルールを決めて終わりではありません。何をモックし、何を実物のまま検証するかの基準がチームで揃っていないと、人によってモック地獄と密結合が同時に発生します。単体テストではモックを最小限に絞る、リポジトリはフェイクで置く、E2Eは主要導線だけ実物で通す——といった方針をコードレビューの観点に落とし込み、CI/CDで層ごとに実行タイミングを分けて初めて、戦略として社内に定着します。

とはいえ、既存システムの改修と並行してテスト基盤を整える体力を確保できないケースは少なくありません。密結合コードの依存分離、モック方針の標準化、CIへのテスト組み込み、内製チームへの設計移譲を伴走で進めたい場合は、Webシステムの保守運用・内製化支援で、テスト戦略の設計から運用定着までを一緒に組み立てられます。外注で作って終わりにせず、自走できる状態まで引き渡すことを前提に設計します。

モックとスタブの使い分けで実務からよく寄せられる質問への回答

モックを実務へ落とし込む際に、検索でよく問われる論点を5つ取り上げます。

モックとスタブの違いを一言でいうと何ですか?

「何を検証するか」が違います。スタブはテスト対象に決まった入力(戻り値)を与えるための道具で、確かめるのはテスト対象が返す状態です。モックは依存が正しく呼ばれたか(回数・引数)という相互作用そのものを検証する道具です。戻り値を差し替えたいだけならスタブ、副作用が正しく起きたことを保証したいならモック、と目的で選び分けてください。

モック・スタブ・スパイ・フェイクはどう使い分けますか?

役割で選びます。値を返すだけならスタブ、呼ばれ方を検証するならモック、スタブとして値を返しつつ後から呼び出し履歴も確認したいならスパイ、インメモリDBのように本物に近い動作が欲しいならフェイクです。実務ではすべてを厳密に呼び分ける必要はなく、「入力を与える道具」と「相互作用を検証する道具」を区別できれば十分に困りません。

モックは使わないほうがよいのですか?

使わないほうがよいのではなく、使いどころを絞るべきです。副作用(通知・登録・決済など)が正しく起きたことを保証したい場面ではモックが素直に効きます。一方、副作用のない純粋なロジックや値オブジェクトはモックせず本物のまま呼び、複数回の読み書きの整合を確かめたい依存はフェイクに置くほうが、テストが実装手順に縛られず壊れにくくなります。

モック地獄とは何で、どう見分けますか?

あらゆる依存をモック化し、テストが内部実装の手順に密着した状態を指します。兆候は3つで、1テストのモック設定が長大になる、メソッドの呼び出し回数まで細かく検証している、振る舞いを変えていないのにリファクタリングで大量に赤くなる——このいずれかが出ていれば過剰モックです。是正は、副作用のない依存のモックを外し、DB系はフェイクへ置き換え、検証を「変えてはいけない副作用」に絞ることです。

Pythonやjavascriptでモックはどう書きますか?

Pythonは標準ライブラリのunittest.mockを使い、return_valueで戻り値を設定し、assert_called_once_with()で呼び出しを検証します。JavaScriptはJestのjest.fn()jest.mock()でモック関数を作り、toHaveBeenCalledWith()で検証します。いずれも戻り値の設定(スタブ的機能)と呼び出しの検証(モック的機能)を同じAPIで扱うため、同一オブジェクトが文脈で役割を変える点を意識するのが読み違え防止のコツです。

関連記事

資料請求

RELATED POSTS 関連記事