[解決済み] モックオブジェクトは何のためにあるのか?
質問
私はユニットテストの初心者なのですが、「モックオブジェクト」という言葉をよく耳にします。モックオブジェクトとは何か、そしてユニットテストを書くときに通常どのような目的で使われるのか、素人目にもわかるように説明してもらえませんか?
どのように解決するのですか?
ユニットテストは初めてということで、モックオブジェクトを"素人用語"で質問されたので、素人向けの例でやってみます。
ユニットテスト
このシステムの単体テストを想像してください。
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個準備完了(ダミーのホットドッグをウェイターに渡す)
ウェイター に テストドライバー : フライドポテトをどうぞ(他の注文のフライドポテトをテストドライバーに渡す)テストドライバー は、予想外のフライドポテトに注目してください。テストは失敗!ウェイターが間違った皿を返してきた。
モックオブジェクトとスタブの違いを明確に理解するには、スタブベースの対照的な例がないと難しいかもしれませんが、この回答はすでに長すぎます :-)
また、これはかなり単純化された例であり、モッキングフレームワークは包括的なテストをサポートするために、コンポーネントから期待される動作のかなり洗練された仕様を可能にすることに注意してください。 モック・オブジェクトやモッキング・フレームワークに関する多くの資料がありますので、より詳しい情報を得ることができます。
関連
-
[解決済み] jest.fn()の機能と使い方を教えてください。
-
[解決済み] MOCKITOとは何か、Junitとはどう違うか
-
[解決済み] モックとスタブの違いは何ですか?
-
[解決済み] Mockitoでvoidメソッドをモックする方法
-
[解決済み] フェイク、モッキング、スタビングの違いとは?
-
[解決済み] モッキングとは?
-
[解決済み] データベース駆動型アプリケーションのユニットテストに最適な戦略とは?
-
[解決済み】テストのInitメソッドでHttpContext.Currentをモックする
-
[解決済み] テスト駆動開発のデメリット?[クローズド]
-
[解決済み] "エラー。Karma-Jasmineのユニットテストケースを書いているときに「No provider for router」というエラーが発生しました。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】Assert.Fail()はバッドプラクティスとみなされるか?
-
[解決済み] ユニットテストの妥当なコードカバレッジは何%ですか(とその理由)?[クローズド]です。
-
[解決済み] モッキングとは?
-
[解決済み] NUnit vs. MbUnit vs. MSTest vs. xUnit.net [終了しました。]
-
[解決済み】mochaのテスト用ディレクトリを指定するには?
-
[解決済み] GUIをユニットテストするにはどうしたらいいですか?
-
[解決済み] 既存のプロダクションプロジェクトにユニットテストをうまく追加することができますか?もしそうなら、どのように、そして、それは価値があるのでしょうか?
-
[解決済み] GTestとCMakeを使った作業の始め方
-
[解決済み] "エラー。Karma-Jasmineのユニットテストケースを書いているときに「No provider for router」というエラーが発生しました。
-
[解決済み] ユニットテストとは、どのようなもので、どのように行うのですか?[重複あり]