1. ホーム
  2. unit-testing

[解決済み] モックオブジェクトは何のためにあるのか?

2022-04-14 18:48:13

質問

私はユニットテストの初心者なのですが、「モックオブジェクト」という言葉をよく耳にします。モックオブジェクトとは何か、そしてユニットテストを書くときに通常どのような目的で使われるのか、素人目にもわかるように説明してもらえませんか?

どのように解決するのですか?

ユニットテストは初めてということで、モックオブジェクトを"素人用語"で質問されたので、素人向けの例でやってみます。

ユニットテスト

このシステムの単体テストを想像してください。

cook <- waiter <- customer

のような低レベルのコンポーネントをテストすることは、一般に容易に想像がつきます。 cook :

cook <- test driver

テストドライバは単に異なる料理を注文し、料理人がそれぞれの注文に対して正しい料理を返すかどうかを確認します。

ウェイターのように、他のコンポーネントの動作を利用する中間コンポーネントをテストするのは難しいです。 素朴なテスターは、cookコンポーネントをテストしたのと同じ方法でwaiterコンポーネントをテストするかもしれません。

cook <- waiter <- test driver

テストドライバは、異なる料理を注文し、ウェイターが正しい料理を返すことを確認します。 残念ながら、このウェイターコンポーネントのテストは、クックコンポーネントの正しい動作に依存する可能性があることを意味します。 例えば、非決定的な動作(メニューにシェフのサプライズがある)、多くの依存関係(スタッフ全員がいないと料理ができない)、多くのリソース(高価な材料を必要としたり、調理に1時間かかる料理がある)などが挙げられます。

これはウェイターのテストなので、理想を言えば、コックではなくウェイターだけをテストしたいのです。 具体的には、ウェイターが客の注文を料理人に正しく伝え、料理人の料理を客に正しく届けることを確認したいのです。

ユニットテストとは、ユニットを独立してテストすることなので、より良いアプローチは、テスト対象のコンポーネント(ウェイター)を ファウラーがテストダブルズ(ダミー、スタブ、フェイク、モック)と呼ぶもの .

    -----------------------
   |                       |
   v                       |
test cook <- waiter <- test driver

ここで、テストクックはテストドライバと共謀しています。 理想的には、テスト対象のシステムは、テストクックを簡単に代用できるように設計されています ( インジェクション ) を使って、プロダクションコードを変更することなく (例えば、ウェイターのコードを変更することなく) ウェイターと連携することができます。

モックオブジェクト

さて、テストクック(テストダブル)は、さまざまな方法で実装することができます。

  • 偽の料理人 - 冷凍食品と電子レンジを使って、料理人のふりをする人。
  • スタブコック - ホットドッグ屋さんで、何を頼んでも必ずホットドッグを出してくる人、あるいは
  • 模擬コック - おとり捜査でコックのふりをするスクリプトに従った潜入捜査官。

参照 Fowlerの記事で、fakeとstubsとmockとdummiesについて、より詳しく説明しています。 しかし、今はモック・クックに焦点を当てましょう。

    -----------------------
   |                       |
   v                       |
mock cook <- waiter <- test driver

ウェイターコンポーネントのユニットテストの大部分は、ウェイターがクックコンポーネントとどのように相互作用するかに焦点を当てています。モックベースのアプローチでは、正しい相互作用が何であるかを完全に特定し、それがうまくいかなくなったときに検出することに焦点を当てます。

モックオブジェクトは、テスト中に何が起こるか(例えば、どのメソッドコールが呼び出されるか、など)をあらかじめ知っており、どのように反応するか(例えば、どのような戻り値を提供するか)も知っています。 モックは、実際に起こったことと想定していたことが異なるかどうかを示します。 テストケースごとに独自のモックオブジェクトを作成して、 そのテストケースで想定される振る舞いを実行することもできますが、 モッキングフレームワークでは、そのような振る舞いの仕様をテストケースの中で直接わかりやすく示すように努めています。

モックを使ったテストにまつわる会話は、こんな感じでしょうか。

<ブロッククオート

テストドライバー から モックコック : ホットドッグの注文を受け、このダミーホットドッグを渡す。

テストドライバー (顧客を装う)から ウェイター : ホットドッグをお願いします

ウェイター モックコック : ホットドッグ1個ください

モックコック ウェイター : を注文してください。ホットドッグ1個準備完了(ダミーのホットドッグをウェイターに渡す)

ウェイター テストドライバー : ホットドッグです(ダミーのホットドッグを渡す)

テストドライバー : テスト成功!

しかし、我々のウェイターは新しいので、このようなことが起こり得るのです。

テストドライバー から モックコック : ホットドッグの注文を受け、このダミーホットドッグを渡す。

テストドライバー (顧客を装う)から ウェイター : ホットドッグをお願いします

ウェイター モックコック : ハンバーガー1個ください

モックコック テストを停止します。 ホットドッグの注文を受けるように言われたんだけど!?

テストドライバー は問題点を指摘しています:TEST FAILED! - ウェイターが注文を変更した

または

テストドライバー から モックコック : ホットドッグの注文を受け、このダミーホットドッグを渡す。

テストドライバー (顧客を装う)から ウェイター : ホットドッグをお願いします

ウェイター モックコック : ホットドッグ1個ください

モックコック ウェイター : を注文してください。ホットドッグ1個準備完了(ダミーのホットドッグをウェイターに渡す)

ウェイター テストドライバー : フライドポテトをどうぞ(他の注文のフライドポテトをテストドライバーに渡す)

テストドライバー は、予想外のフライドポテトに注目してください。テストは失敗!ウェイターが間違った皿を返してきた。

モックオブジェクトとスタブの違いを明確に理解するには、スタブベースの対照的な例がないと難しいかもしれませんが、この回答はすでに長すぎます :-)

また、これはかなり単純化された例であり、モッキングフレームワークは包括的なテストをサポートするために、コンポーネントから期待される動作のかなり洗練された仕様を可能にすることに注意してください。 モック・オブジェクトやモッキング・フレームワークに関する多くの資料がありますので、より詳しい情報を得ることができます。