LASSIC Media らしくメディア
テストダブルとは|モック/スタブの違いと使い分け
システムの自動テストを書き進めていくと、データベースや外部API、現在時刻、メール送信といった「本物の依存」に何度も突き当たります。テストのたびに本物のデータベースへ接続したり、実際に外部サービスへリクエストを飛ばしたりしていては、実行に時間がかかるうえ、ネットワークの状態や外部側の都合によって結果がふれてしまうこともあるでしょう。
こうした本物の依存を、テストの間だけ代役に置き換える技法群を、テストダブルと呼びます。モックやスタブという言葉を耳にしたことがある方は多いはずですが、両者の違いや使い分けまで説明できる方は意外と少ないのではないでしょうか。この記事では、発注者やプロジェクトマネージャー、品質を管理する立場の方に向けて、テストダブルという考え方の骨子と、外部に開発を委託する際に押さえておきたい観点を整理します。
目次
テストダブルとは
テストダブルとは、自動テストにおいて、本物の依存先(データベース・外部API・現在時刻・メール送信サービスなど)の代わりに使う、代役となるオブジェクトやコンポーネントの総称です。映画撮影で危険な場面に本人の代わりに立つ「スタントダブル」と同じ発想で、テストの世界でも本物の代わりを立てる、というわけです。
たとえば注文処理のプログラムをテストするとき、本物の決済APIを毎回呼び出していては、テストの実行時間が延びるうえ、決済側の障害や仕様変更にテストの成否が左右されてしまいます。テストダブルを使えば、決済APIの代わりに「常に成功を返すだけの軽い部品」を差し込み、注文処理そのもののロジックだけを切り出して検証できるようになるのです。
この記事で扱うのは、あくまで「テストダブルという考え方」そのものです。ホワイトボックス・ブラックボックスといったテスト技法の分類や、画面操作をなぞって自動確認するE2Eツールの話には立ち入らず、単体テストの中で依存をどう切り離すか、という一点に絞って見ていきます。
この記事のポイント
- テストダブルは、自動テストで本物の依存(DB・外部API・時刻・メール送信など)の代わりに使う代役の総称です。
- ダミー・スタブ・スパイ・モック・フェイクという種類があり、確かめたい内容によって使い分けます。
- 使いすぎると実装に密結合して壊れやすくなるため、結合テストとの役割分担が欠かせません。
なぜテストダブルが必要なのか
自動テストは、書いたコードが期待通りに動くかを、人手を介さず繰り返し確かめる仕組みです。この繰り返しの速さと安定性こそが値打ちなのですが、テストのたびに本物のデータベースや外部サービスへアクセスしていると、その値打ちが損なわれてしまいます。
外部APIの呼び出しには通信の時間がかかり、何百件ものテストを一度に走らせるたびに、待ち時間が積み重なっていくものです。加えて、外部サービス側が一時的に不調であれば、自分たちのコードそのものに問題がなくてもテストが落ちてしまい、原因の切り分けに余計な手間がかかることもあるでしょう。テストダブルで依存を切り離しておけば、こうした外部要因からテストの結果を守れます。
もう一つの理由が、再現しにくい状況を意図的に作り出せる点にあります。「決済APIがタイムアウトしたとき」「口座残高が不足していたとき」といった、本物の環境では狙って起こしにくい状態も、テストダブルに差し替えれば思い通りに再現できるのです。現在時刻に依存する処理、たとえば月末処理や期限切れ判定なども、実際のシステム時計に頼っていては実行日によって結果が変わりかねませんが、時刻を返す部分をテストダブルに置き換えれば、いつ実行しても同じ条件で検証できるようになります。
代表的な種類(ダミー・スタブ・スパイ・モック・フェイク)
テストダブルは一つの技法ではなく、目的に応じていくつかの種類に分かれます。ひとまとめに「モック」と呼んでしまう現場も見かけますが、本来は次のように分類して捉えるのが一般的です。
| 種類 | 主な役割 | 具体例 |
|---|---|---|
| ダミー(Dummy) | 引数を埋めるためだけに渡され、中身は使われない | 呼び出しに必要な空のオブジェクトや仮のID |
| スタブ(Stub) | 呼び出されると、あらかじめ決めた値を返す | 常に「成功」を返す決済APIの代わりの部品 |
| スパイ(Spy) | 呼び出された回数や引数を記録する | メール送信処理が何回呼ばれたかを記録する部品 |
| モック(Mock) | 呼ばれ方そのものが正しいかを検証する | 「特定の引数で1回だけ呼ばれたか」を確認する部品 |
| フェイク(Fake) | 簡易ながら実際に動く実装を持つ | メモリ上だけで動く簡易的なデータベース |
呼び出された記録をどう扱うかで、スパイとモックを分けて説明する整理もあります。呼び出された回数や引数を記録するだけならスパイ、その記録をもとにテスト自身が合否まで判定する仕組みまで含めればモック、という見方です。呼び方には現場ごとに多少の流儀の違いがあるものの、「何を確かめたいか」で使い分けるという考え方は共通しているといえるでしょう。
実際の開発では、これらのテストダブルを一つずつ手書きすることは少なく、多くのプログラミング言語で、モックやスタブを手早く作れるライブラリが用意されています。呼び出しの記録や検証を自動でこなしてくれるため、開発者は「何を、どう振る舞わせたいか」を宣言するだけで済むことがほとんどです。とはいえ、道具が便利になったからといって、どの種類のテストダブルを使うべきかという判断そのものが不要になるわけではありません。
モックとスタブの違い
テストダブルの種類の中でも、とくに混同されやすいのがスタブとモックです。どちらも本物の代わりに差し込む部品という点は同じですが、テストで確かめたい対象が異なります。
スタブを使うテストは、状態検証と呼ばれるやり方をとります。スタブに決まった値を返させておき、その値を受け取ったプログラムが最終的にどんな結果を出したか、という結果の状態を確認するのです。決済APIのスタブが成功を返したとき、注文が正しく「完了」という状態になっているかを確かめる、といった使い方がこれにあたります。
一方でモックを使うテストは、振る舞い検証と呼ばれます。プログラムが結果として何を返したかではなく、途中で「誰を、どんな引数で、何回呼び出したか」という過程そのものを確認の対象にするのです。「注文確定処理の中で、メール送信の部品がちょうど1回呼ばれたか」を確かめたい場合は、モックの出番となるでしょう。
どちらが優れているという話ではなく、確かめたいことに応じて選ぶのが筋です。最終的な結果さえ合っていればよい場面ではスタブで足りますし、通知の送信や外部システムへの書き込みといった副作用を伴う処理が、正しい回数・タイミングで呼ばれたかを確かめたい場面では、モックが向いています。
使いどころと使いすぎの注意点
テストダブルは便利な道具ですが、何にでも使えばよいというものではありません。使いすぎると、かえってテストの値打ちを下げてしまう場面があるのです。
とりわけ注意したいのが、モックを多用しすぎて内部の実装細部にテストが密結合してしまうケースでしょう。「この関数が、この順番で、この引数で呼ばれたか」という検証を積み重ねすぎると、実装を少し書き換えただけでテストが軒並み落ちるようになりかねません。テストが実装の変更を妨げる足かせになってしまっては、本末転倒だといえます。
また、依存のすべてをテストダブルに置き換えてしまうと、部品同士を組み合わせたときに初めて表面化する不具合を見逃しやすくなります。個々の部品は単体テストで問題なく通っていても、実際に本物のデータベースやAPIとつないだ途端に動かない、という事態は珍しくありません。
単体テストではテストダブルで依存を切り離して素早く回し、結合テストやステージング環境でのテストでは本物、あるいはそれに近いものを使って組み合わせの正しさを確かめる。こうした役割分担を意識すると、両方の利点を活かしやすくなるでしょう。テストダブルは単体テストを支える道具であって、結合テストの代わりにはならない、と捉えておくのが実務的な線引きになります。
目安としては、「壊れやすさ」と「危うさ」の両面から依存先を眺めてみるとよいでしょう。仕様がまだ固まっていない自社の内部ロジックまでモックで細かく縛ってしまうと、仕様変更のたびにテストの手直しが発生します。一方、外部の決済サービスや通知基盤のように、失敗した際の影響が大きい依存先については、テストダブルで日常的な単体テストを支えつつ、結合テストや受け入れテストの段階で本物との接続を別途確かめておく、という二段構えが現実的な落としどころになります。
外注・委託時に品質を保つ観点
システム開発を外部のベンダーへ委託する場合、テストダブルの使い方は成果物の見えにくい品質を左右する部分でもあります。発注側が押さえておきたい観点を挙げます。
テストの構成方針を確認する
納品前に、単体テストと結合テストがどのような比率で組まれているのかを確認しておくとよいでしょう。すべてがテストダブルで固めた単体テストばかりで、本物に近い環境で確かめる結合テストがほとんど無いという構成では、組み合わせ部分の不具合が本番環境で初めて見つかるおそれが残ります。
テストダブルの使いどころに偏りがないかを尋ねる
外部API呼び出しや決済処理など、失敗したときの影響が大きい依存先ほど、テストダブルでの検証に加えて、実際の連携先を使った確認の機会を設けているかを尋ねる価値があります。「どの依存をテストダブルに置き換え、どの依存は本物で確かめているか」を一覧で示してもらえると、判断の材料になるはずです。
テストコードも成果物として引き継ぐ
テストダブルを使ったテストコードは、納品物の一部として引き継ぎの対象に含めておきたいところです。保守や改修を別のベンダーへ引き継ぐ際、テストの意図が読み取れないと、既存のテストダブルを安易に書き換えられ、品質を検証する網そのものが崩れてしまう事態にもつながりかねません。
テスト戦略を見積もりの段階からすり合わせる
テストダブルの設計や、どこまで結合テストを組むかは、見積もりの工数にも直結する項目です。着手後になって「単体テストしか想定していなかった」「本物のAPIとの結合確認は別料金だった」といった認識のずれが表面化すると、スケジュールにも予算にも響いてきます。企画・要件定義の段階で、テストの範囲と役割分担についてすり合わせておくことが、後々の手戻りを防ぐ近道になるでしょう。
まとめ
- テストダブルは、自動テストで本物の依存(DB・外部API・時刻・メール送信など)の代わりに使う代役の総称である。
- 依存を切り離すことで、テストの実行を速く安定させ、再現しにくい状況も意図的に作り出せる。
- ダミー・スタブ・スパイ・モック・フェイクという種類があり、確かめたい内容に応じて使い分ける。
- スタブは結果の状態を確認する状態検証、モックは呼ばれ方そのものを確認する振る舞い検証に向く。
- 使いすぎると実装に密結合して壊れやすくなるため、結合テストとの役割分担を意識する必要がある。
よくある質問
モックとスタブは、何が違いますか。
確認する対象が異なります。スタブは決まった値を返す代役で、その値を受け取った結果としてプログラムがどんな状態になったかを確かめる「状態検証」に使われます。モックは、部品が「誰を、どんな引数で、何回呼び出したか」という過程そのものを確認する「振る舞い検証」に使われるのです。結果だけを見たいのか、呼ばれ方まで見たいのかによって、どちらを使うかが変わってきます。
テストダブルを使いすぎると、どうなりますか。
実装の細かい呼び出し方までモックで固めすぎると、テストが実装の細部に密結合してしまい、少し書き換えただけでテストが軒並み落ちるようになりかねません。また依存のすべてをテストダブルに置き換えると、部品同士を組み合わせたときに初めて出る不具合を見逃しやすくなります。単体テストはテストダブルで、結合テストは本物に近いもので、という役割分担を意識することが大切です。
テストダブルには、どんな種類がありますか。
代表的なものとして、引数を埋めるだけのダミー、決まった値を返すスタブ、呼び出しの記録を残すスパイ、呼ばれ方そのものを検証するモック、簡易ながら実際に動く実装を持つフェイクの五つが挙げられます。すべてをひとまとめに「モック」と呼ぶ現場もありますが、確かめたい内容に応じてこれらを使い分けるのが本来の考え方です。
外部委託先の品質は、テストダブルの使い方から判断できますか。
判断材料の一つにはなります。テストダブルで固めた単体テストしか用意されておらず、本物に近い環境で確かめる結合テストがほとんど無い場合、組み合わせ部分の不具合が本番で初めて見つかるおそれが残るためです。どの依存をテストダブルに置き換え、どの依存は本物で確認しているかを一覧で示してもらえるかどうかは、確認しておきたいポイントでしょう。
著者:テレリモ総研編集部 鈴木 亮佑
LASSICでは、国内ニアショア開発体制を活かし、自動テストの設計方針づくりからテストコードの実装、公開済みシステムのテスト体制の見直しまでを一貫して支援する体制です。要件定義の段階から実装、テスト、リリース後の運用・保守まで、工程を分けずに任せられる点も強みでしょう。品質を保ちながら開発のスピードを上げたいとお考えの際も、ご相談いただけます。
ご不明な点はお問い合わせフォームからもご連絡いただけます。