スタブとは?ドライバ・モックとの違いと使い分け【早見表つき】

ソフトウェアテストの現場で必ず出てくる言葉が スタブ(Stub) です。
ただ、実際に調べ始めると「ドライバとどう違うのか」「モックとは別物なのか」で混乱しがちです。この記事では、スタブの意味・ドライバとの違い・モックとの違いを早見表で整理したうえで、Java での作り方、使い分けの判断基準、失敗しやすいパターンまで実務目線で解説します。
スタブとは?
スタブとは、テスト対象が呼び出す「下位モジュール」の代わりに置く、あらかじめ決めた値を返すだけの仮の部品です。
Stub は英語で「切り株」「半券」を意味します。本体から切り離された残りの部分、つまり「中身のない代用品」というニュアンスがそのまま使われています。
なぜスタブが必要なのか
あるモジュールをテストしたくても、それが呼び出す相手が揃っていないことは日常的に起こります。
- まだ実装されていない:別チームが開発中で、来月にならないと完成しない
- 呼び出すと副作用がある:本番の決済 API、メール送信、外部への課金
- 遅い・不安定:DB アクセスやネットワーク通信でテストが数分かかる
- 再現できない:タイムアウトやサーバーエラーなど、狙って起こせない状況
スタブを置けば、これらを待たずにテスト対象だけを切り離して検証できます。「呼ばれたら常に成功を返す」「呼ばれたらタイムアウト例外を投げる」といった振る舞いを固定できるため、テスト結果が毎回同じになる点も重要です。
スタブ・ドライバ・モックの違い早見表
混同されやすい 3 つを、まず表で押さえます。
| 用語 | 置き換える対象 | 役割 | 検証の対象 |
|---|---|---|---|
| スタブ | 呼び出される側(下位モジュール) | 決められた値を返す | 結果(状態) |
| ドライバ | 呼び出す側(上位モジュール) | テスト対象を呼び出す | 結果(状態) |
| モック | 呼び出される側(下位モジュール) | 値を返し、かつ呼び出しを記録する | 相互作用(振る舞い) |
覚え方はシンプルです。
スタブは「下」を埋める。ドライバは「上」を埋める。
モックは「下」を埋めたうえで、呼ばれ方まで見張る。
スタブとドライバの違い
スタブとドライバは置き換える位置が正反対です。ここを取り違えると会話が噛み合わなくなります。
位置関係のイメージ
[ドライバ] ← 上位モジュールの代わり(テスト対象を呼び出す)
↓
[テスト対象]
↓
[スタブ] ← 下位モジュールの代わり(決まった値を返す)テスト対象より下が未完成ならスタブ、上が未完成ならドライバを用意する、と覚えると迷いません。
結合テストの進め方で使うものが変わる
結合テストをどの順番で組み上げるかによって、必要になる代替部品が決まります。
| 手法 | 進め方 | 必要なもの | 特徴 |
|---|---|---|---|
| トップダウンテスト | 上位モジュールから順に結合 | スタブ | 主要な処理の流れを早期に確認できる |
| ボトムアップテスト | 下位モジュールから順に結合 | ドライバ | 基盤部分の品質を早期に固められる |
| サンドイッチテスト | 上下から同時に結合 | 両方 | 並行して進められるが準備コストが高い |
「スタブが必要」と言われたら、それはトップダウンで進めているというサインでもあります。
スタブとモックの違い
スタブとモックはどちらも「呼び出される側」を置き換えるため、位置は同じです。違うのは何を検証するかです。
スタブは「状態検証」のためのテストダブルで、テスト対象に特定の入力を提供することを主な目的としています。スタブは事前に定義された応答を返すだけで、呼び出されたかどうかを検証する機能はありません。
一方、モックは「振る舞い検証」のためのテストダブルで、テスト対象コードが依存オブジェクトを正しく操作しているかを検証します。モックはスタブの機能に加えて、どのメソッドが何回呼び出されたか、どのような引数で呼び出されたかなどを記録し、検証する機能を持っています。
使い分けの判断基準
判断はこの一点で決まります。
- 「結果」を検証したい → スタブを使う
- 「相互作用」を検証したい → モックを使う
例えば、メールサービスを呼び出すコードをテストする場合、実際にメールが送信されたかどうかを確認したいならモックを使用し、メール送信の結果によって処理が正しく分岐しているかを確認したいならスタブを使用するのが適切です。
迷ったときはまずスタブを検討してください。モックは「呼び出し方」まで固定してしまうため、あとで実装を変えたときにテストが壊れやすくなります。
テストダブルの5分類(スタブはその1つ)
スタブやモックをまとめた総称が テストダブル(Test Double) です。映画の「スタントダブル(代役)」が語源で、書籍『xUnit Test Patterns』では次の 5 種類に分類されています。
| 種類 | 役割 | 典型的な使い方 |
|---|---|---|
| ダミー(Dummy) | 渡すだけで使われない | 引数の数を合わせるための null 相当の値 |
| スタブ(Stub) | 決まった値を返す | 「常に成功を返す」認証サービス |
| スパイ(Spy) | 実物として動きつつ記録する | 実際に動かしたうえで呼び出し回数を確認 |
| モック(Mock) | 期待した呼ばれ方かを検証する | 「send が1回呼ばれること」を保証 |
| フェイク(Fake) | 簡易だが本当に動く実装 | インメモリ DB、H2、SQLite |
実務ではこの区別が厳密に守られないこともあり、モックライブラリで作ったものをすべて「モック」と呼ぶ現場も多くあります。用語より「何を検証したいか」を会話で揃えるほうが重要です。
Javaでのスタブ・モックの作り方
ここでは、ユーザー情報を取得する UserService をテストする例で、スタブとモックの実装を比較します。前提となるインターフェースは次のとおりです。
public interface UserRepository {
User findById(Long id);
}スタブを手書きで作る
もっとも基本的な方法は、インターフェースを実装した固定値を返すクラスを自分で書くやり方です。
// スタブクラスの実装
class StubUserRepository implements UserRepository {
@Override
public User findById(Long id) {
// 何を渡されても同じユーザーを返すだけ
return new User(1L, "テストユーザー");
}
}
@Test
public void testUserServiceWithStub() {
// スタブを注入
UserRepository stubRepository = new StubUserRepository();
UserService userService = new UserService(stubRepository);
// テスト実行
User user = userService.getUserById(1L);
// 「結果」を検証する
assertEquals("テストユーザー", user.getName());
}ライブラリに依存せず、動きが読んですぐ分かるのが利点です。一方で、返す値のパターンを増やすたびにクラスが増えていく欠点があります。
Mockitoでスタブを作る
Java で最も一般的なのが Mockito です。when(...).thenReturn(...) で戻り値を決めれば、それはスタブとして機能します。
@Test
public void testUserServiceWithMockito() {
UserRepository repository = mock(UserRepository.class);
// 戻り値を固定する = スタブとしての使い方
when(repository.findById(1L))
.thenReturn(new User(1L, "テストユーザー"));
UserService userService = new UserService(repository);
User user = userService.getUserById(1L);
assertEquals("テストユーザー", user.getName());
}例外を返させたいときは thenThrow を使います。外部システムでは再現しにくいエラー系のテストが簡単に書けます。
// タイムアウトを再現する
when(repository.findById(1L))
.thenThrow(new TimeoutException("接続がタイムアウトしました"));モックとして使う(verifyを足す)
同じ Mockito でも、verify(...) で呼び出しを検証した瞬間にモックとしての使い方になります。
@Test
public void testUserService() {
// モックの作成
UserRepository mockRepository = mock(UserRepository.class);
// モックの振る舞いを定義
when(mockRepository.findById(1L))
.thenReturn(new User(1L, "テストユーザー"));
// テスト対象のサービスにモックを注入
UserService userService = new UserService(mockRepository);
// テスト実行
User user = userService.getUserById(1L);
// 結果の検証
assertEquals("テストユーザー", user.getName());
// 呼び出しの検証 = ここがモックの本質
verify(mockRepository, times(1)).findById(1L);
}つまり Mockito では「スタブかモックか」はクラスの種類ではなく、verify を書くかどうかで決まります。この点が混乱の大きな原因になっています。
ドライバの例
ドライバは「テスト対象を呼び出すだけの仮の上位モジュール」です。JUnit のテストメソッド自体が、実質的にドライバの役割を果たしています。
// 上位モジュールがまだ無いので、代わりに呼び出す=ドライバ
public class UserServiceDriver {
public static void main(String[] args) {
UserService service = new UserService(new StubUserRepository());
User user = service.getUserById(1L);
System.out.println("取得結果: " + user.getName());
}
}スタブ・モックを使うメリット
テストの分離と信頼性向上
モックとスタブを使用することで、テスト対象のコードを外部依存から完全に分離できます。これにより、テストが外部システムの状態に左右されることなく、常に一貫した結果を得ることができます。例えば、データベースやAPIの状態に関係なくテストが実行できるため、テストの信頼性が向上します。
開発スピードの向上
実際の依存コンポーネントがまだ開発中であっても、モックやスタブを使用することでテストを先行して作成できます。これにより、並行開発が可能になり、開発全体のスピードが向上します。
エッジケースのテストが容易に
外部システムでは再現が難しいエラー状態や特殊なレスポンスも、モックやスタブを使用することで簡単に再現できます。例えば、ネットワークタイムアウトやサーバーエラーなどの例外的な状況をシミュレートし、アプリケーションの堅牢性をテストできます。
テスト実行の高速化
実際のデータベースアクセスやネットワーク通信は時間がかかりますが、モックやスタブを使用することでこれらの処理を省略できるため、テストの実行時間が大幅に短縮されます。これにより、開発者は頻繁にテストを実行できるようになり、問題の早期発見につながります。
スタブのデメリットと注意点
メリットの裏返しとして、次の点には注意が必要です。
- 本物と食い違う可能性がある:スタブが返す値と実際のモジュールの戻り値がずれていると、結合したときに初めて不具合が出ます
- 作成・保守にコストがかかる:仕様変更のたびにスタブ側も直す必要があります
- 消し忘れが事故につながる:本番コードにスタブが残ると、常に固定値を返す重大な不具合になります
スタブでテストが通っても、それは「本物と繋いだときに動く」保証にはならない。
最終的には実際のモジュールを結合したテストが必要です。
テスト駆動開発(TDD)での活用
テスト駆動開発(TDD)では、「テスト→実装→リファクタリング」のサイクルを繰り返しますが、モックとスタブはこのプロセスを効率化する重要なツールです。
- テスト作成フェーズ:まず、必要な機能のテストを書きます。この段階で、依存コンポーネントのモックやスタブを定義します。
- 実装フェーズ:テストを通過させるために最小限のコードを実装します。モックやスタブを使用することで、まだ実装されていない依存コンポーネントがあっても開発を進められます。
- リファクタリングフェーズ:コードの品質を改善しつつ、テストが引き続き通過することを確認します。
TDDでは、モックを使って「どのように他のコンポーネントと相互作用するか」を先に定義することで、明確なインターフェース設計が促進されます。これにより、コンポーネント間の結合度が低く、凝集度の高い設計が自然と生まれやすくなります。
よくある失敗パターンと回避策
モックとスタブは強力なツールですが、誤った使い方をすると問題を引き起こす可能性があります。
過剰なモック化
すべての依存関係をモック化すると、テストが実装の詳細に過度に結びつき、リファクタリングが難しくなります。
回避策: 必要最小限のモック化を心がけ、実際のオブジェクトを使用できる場合はそちらを優先しましょう。特に、値オブジェクトやエンティティなどの単純なオブジェクトはモック化せず、実際のインスタンスを使用するのが良いでしょう。
モックとスタブの混同
モックとスタブの違いを理解せずに使用すると、テストの意図が不明確になり、メンテナンスが困難になります。
回避策: テストの目的を明確にし、状態を検証したい場合はスタブを、振る舞いを検証したい場合はモックを使用するというルールを守りましょう。
脆弱なテスト
実装の詳細に過度に依存したテストは、小さなコード変更でも失敗するようになり、メンテナンスコストが高くなります。
回避策: 公開インターフェースに対してテストを行い、内部実装の詳細にはあまり依存しないようにしましょう。また、モックの検証は必要最小限に留め、過度に厳密な検証は避けるべきです。
スタブの削除忘れ
本物のモジュールが完成したあともスタブが残っていると、テストが「常に成功する」状態になり、不具合を検出できません。
回避策: スタブには命名規則(Stub 接頭辞など)を付け、結合が完了した時点で置き換える箇所を追跡できるようにしておきましょう。
クラウド環境でのスタブ・モック活用術
クラウドベースのアプリケーション開発では、外部サービスとの連携が多くなるため、モックとスタブの重要性がさらに高まります。
クラウドサービスのモック化
AWS、Google Cloud、Azureなどのクラウドサービスを利用するアプリケーションをテストする場合、実際のクラウドリソースを使用すると、コストがかかる上にテストの再現性が低下します。
解決策: LocalStack(AWS APIのローカルエミュレーション)やAzurite(Azure Storageのエミュレーター)などのツールを使用して、クラウドサービスをローカルで模倣できます。これにより、実際のクラウドリソースを使用せずにテストが可能になります。
主なスタブ・モックツール
| ツール | 対象 | 特徴 |
|---|---|---|
| Mockito | Java | デファクトスタンダード。スタブもモックも作れる |
| MockK | Kotlin | コルーチンなど Kotlin 固有の機能に対応 |
| WireMock | HTTP API | REST API やマイクロサービスのテストに最適 |
| Mountebank | 分散システム | 複数プロトコルに対応したモックサーバー |
| Testcontainers | DB・ミドルウェア | Docker で本物を起動。モックより実環境に近い |
| LocalStack | AWS | AWS API をローカルでエミュレート |
これらのツールを活用することで、複雑なクラウド環境でも効率的なテストが可能になります。モックとスタブを適切に使い分け、テスト戦略に組み込むことで、品質の高いソフトウェアを効率的に開発できるでしょう。
よくある質問
スタブとドライバ、どちらを先に作るべきですか?
結合の進め方によります。上位モジュールから組み上げるトップダウンならスタブ、下位から組み上げるボトムアップならドライバが必要です。画面や主要な処理の流れを早く確認したい場合はトップダウン=スタブ優先が一般的です。
Mockitoで作ったものはスタブですか、モックですか?
使い方によって変わります。when(...).thenReturn(...) で戻り値を決めるだけならスタブ、verify(...) で呼び出しを検証すればモックとしての使い方になります。生成に使うメソッド名が mock() であることが、混乱を招く一因です。
スタブとフェイクはどう違いますか?
スタブは決まった値を返すだけですが、フェイクは簡易的ながら本当に動く実装を持ちます。インメモリ DB がその代表で、登録した値をきちんと取り出せます。ロジックを含む処理を試したいときはフェイクが適しています。
スタブは単体テストと結合テストのどちらで使いますか?
どちらでも使います。単体テストでは外部依存を切り離す目的で、結合テストではトップダウンで未完成の下位モジュールを埋める目的で使われます。
まとめ
- スタブは、テスト対象が呼び出す下位モジュールの代わりに、決まった値を返す仮の部品
- ドライバは逆に、テスト対象を呼び出す上位モジュールの代わり
- モックはスタブと同じ位置に置くが、呼び出し方まで検証する点が異なる
- 「結果」を見たいならスタブ、「相互作用」を見たいならモック
- スタブで通ったテストは、本物と繋いだ動作を保証しない。結合テストは必ず行う
モックとスタブを適切に使い分け、テスト戦略に組み込むことで、品質の高いソフトウェアを効率的に開発できます。
次に読むならこの記事
テストの手戻りを減らしたい方へ
テスト仕様書のExcelテンプレートを無料で配布しています。自社で整備する場合も、外部に任せる場合も、まずは型を持つところから。


