コンピュータ サイエンスでは、モック オブジェクトは、限定された方法で製品オブジェクトを模倣するオブジェクトです。プログラマーは、ソフトウェア テストのテスト ダブルとしてモック オブジェクトを使用する場合があります。モック オブジェクトは、ジェネリック プログラミングでも使用できます。
類推
自動車の設計者が衝突試験用のダミーを使用して車両衝突時の人間を シミュレートするのと同じように、モック オブジェクトはソフトウェア テスターにとって役立ちます。
モチベーション
単体テストでは、モック オブジェクトは複雑な実際のオブジェクトの動作をシミュレートできるため、実際のオブジェクトを単体テストに組み込むのが非現実的または不可能な場合に役立ちます。オブジェクトに次のいずれかの特性がある場合は、代わりにモック オブジェクトを使用すると便利な場合があります。
- 非決定的な結果(例えば、現在の時刻や現在の温度)を提供します。
- 作成または再現が困難な状態(ネットワークエラーなど)がある
- 遅い(例えば、テストの前に準備しなければならない完全なデータベース)
- まだ存在しないか、動作が変わる可能性がある
- テスト目的のみの情報と方法(実際のタスクのためではない)を含める必要がある。
たとえば、特定の時間にベルを鳴らす目覚まし時計プログラムは、タイム サービスから現在の時刻を取得する場合があります。これをテストするには、テストはアラーム時刻まで待機して、ベルが正しく鳴ったかどうかを確認する必要があります。実際の時刻サービスの代わりに模擬タイム サービスを使用する場合は、実際の時刻に関係なく、ベルを鳴らす時刻 (または他の任意の時刻) を提供するようにプログラムできるため、目覚まし時計プログラムを単独でテストできます。
技術的な詳細
モック オブジェクトは、模倣する実際のオブジェクトと同じインターフェイスを持っているため、クライアント オブジェクトは、実際のオブジェクトを使用しているのか、モック オブジェクトを使用しているのかを意識する必要がありません。多くの利用可能なモック オブジェクト フレームワークでは、プログラマーが、モック オブジェクトで呼び出されるメソッド、その順序、メソッドに渡されるパラメーター、および返される値を指定できます。したがって、ネットワーク ソケットなどの複雑なオブジェクトの動作をモック オブジェクトで模倣できるため、プログラマーは、テスト対象のオブジェクトが、そのようなモック オブジェクトのさまざまな状態に適切に応答するかどうかを確認できます。
モック、フェイク、スタブ
モック、フェイク、スタブの定義は文献によって一貫していません。[1] [2] [3] [4] [5] [6]とはいえ、すべて同じインターフェースを公開することでテスト環境内の本番オブジェクトを表します。
名前に関係なく、最も単純な形式は事前に準備された応答 (メソッド スタブなど) を返し、最も複雑な形式は実稼働オブジェクトの完全なロジックを模倣します。
このようなテスト オブジェクトには、各呼び出しのコンテキストを調べるためのアサーションが含まれる場合があります。たとえば、モック オブジェクトは、メソッドが呼び出される順序をアサートしたり、メソッド呼び出し間でのデータの一貫性をアサートしたりする場合があります。
『The Art of Unit Testing』 [7]という本では、モックは、オブジェクトとのやりとりが発生したかどうかを検証することで、テストが失敗したか成功したかを判断するのに役立つ偽のオブジェクトとして説明されています。それ以外のものはすべてスタブとして定義されています。その本では、偽物とは本物ではないものすべてであり、その使用法に基づいて、スタブまたはモックのいずれかになります。
期待値の設定
認可サブシステムがモック化されている例を考えてみましょう。モックオブジェクトは、実際の認可クラスのメソッドと一致するisUserAllowed(task : Task) : boolean[8]メソッドを実装します。実際のクラスには存在しないプロパティも公開すると、多くの利点が得られます。これにより、テストコードで、次の呼び出しでユーザーに権限が付与されるか付与されないかの期待値を簡単に設定できるため、どちらの場合でもシステムの残りの部分の動作を簡単にテストできます。
isAllowed : boolean
同様に、モックのみの設定により、サブシステムへの後続の呼び出しで例外がスローされたり、応答せずにハングしたり、戻ったりすることが保証されます。したがって、バックエンドサブシステムの現実的な障害状態や予想される応答について、クライアントのnull動作を開発してテストすることが可能です。このようなシンプルで柔軟なモック システムがなければ、これらの各状況をテストするのは面倒すぎて、適切な考慮が払われない可能性があります。
ログ文字列の書き込み
モック データベース オブジェクトのsave(person : Person)メソッドには、実装コードがほとんど (またはまったく) 含まれない場合があります。保存のために渡された Person オブジェクトの存在と有効性をチェックすることはできますが (上記の偽物とモックの比較を参照)、それ以外に実装はない可能性があります。
これは機会を逃すことになります。モック メソッドは、パブリック ログ文字列にエントリを追加できます。エントリは、"Person saved" のみでかまいません。[9] : 146–7 また、名前や ID など、person オブジェクト インスタンスの詳細を含めることもできます。テスト コードで、モック データベースに関連するさまざまな操作の後に、ログ文字列の最終的な内容もチェックすると、各ケースで、データベースの保存が正確に期待どおりの数だけ実行されたことを検証できます。これにより、通常は目に見えないパフォーマンス低下のバグを見つけることができます。たとえば、開発者がデータを失うことを恐れて、save()1 回で十分な呼び出しを何度もコーディングした場合などです。
テスト駆動開発での使用
テスト駆動開発(TDD) 方式で作業するプログラマーは、ソフトウェアを作成するときにモック オブジェクトを使用します。モック オブジェクトは、より複雑な実際のオブジェクトのインターフェイス要件を満たし、それらの要件の代わりをします。そのため、プログラマーは、複雑な基礎クラスや連携クラスを呼び出さずに、1 つの領域で機能の作成と単体テストを行うことができます。[9] : 144–5 モック オブジェクトを使用すると、開発者は依存関係を気にせずに、テスト対象システムの動作にテストを集中できます。たとえば、特定の状態にある複数のオブジェクトに基づく複雑なアルゴリズムのテストは、実際のオブジェクトの代わりにモック オブジェクトを使用して明確に表現できます。
複雑さの問題や、関心の分離から得られる利点とは別に、実際の速度の問題もあります。TDD を使用して実際のソフトウェアを開発すると、数百のユニット テストが必要になる場合があります。これらのテストの多くが、データベース、Web サービス、その他のプロセス外またはネットワーク化されたシステムとの通信を引き起こす場合、ユニット テスト スイートはすぐに遅くなりすぎて、定期的に実行できなくなります。これは、悪い習慣や、開発者が TDD の基本原則を維持するのをためらう原因になります。
モック オブジェクトを実際のオブジェクトに置き換えると、エンドツーエンドの機能をさらにテストする必要があります。これらは単体テストではなく 統合テストになります。
制限事項
モック オブジェクトを使用すると、単体テストをテスト対象のコードの実装に密接に結び付けることができます。たとえば、多くのモック オブジェクト フレームワークでは、開発者がテスト対象の実際のオブジェクトによって呼び出されたモック オブジェクト メソッドの順序と回数をチェックできます。そのため、テスト対象のコードを後でリファクタリングすると、すべてのモック オブジェクト メソッドが以前の実装のコントラクトに従っているにもかかわらず、テストが失敗する可能性があります。これは、単体テストではメソッドの内部実装ではなく外部動作をテストする必要があることを示しています。単体テスト スイートの一部としてモック オブジェクトを過度に使用すると、リファクタリングが行われるにつれて、システムの進化中にテスト自体に対して実行する必要があるメンテナンスの量が大幅に増加する可能性があります。進化中にこのようなテストを適切にメンテナンスしないと、実際のクラスのインスタンスを使用する単体テストでは検出されるバグを見逃す可能性があります。逆に、1 つのメソッドをモックするだけでは、実際のクラス全体を設定するよりもはるかに少ない構成で済むため、メンテナンスの必要性が軽減されます。
モックオブジェクトは、モックするオブジェクトの動作を正確にモデル化する必要がありますが、モックするオブジェクトが別の開発者やプロジェクトからのものである場合や、まだ作成されていない場合は、これを実現するのが困難です。動作が正しくモデル化されていない場合、ユニットテストが実行されるのと同じ条件下で実行時に失敗が発生するにもかかわらず、ユニットテストは合格と記録され、ユニットテストが不正確になる可能性があります。[10]
参照
参考文献
- ^ 「.NET Core と .NET Standard を使用したユニット テストのベスト プラクティス - 同じ言語 (フェイク、スタブ、モック) を話しましょう」。Microsoft Docs。2022年 9 月 3 日時点のオリジナルよりアーカイブ。
- ^ ダーシー『ハムレット』(2007年10月21日)。「モックとスタブはスパイではない」。behind the times。2017年6月20日時点のオリジナルよりアーカイブ。
- ^ 「Mocks, Fakes, Stubs and Dummies」XUnitPatterns.com。2024年1月17日時点のオリジナルよりアーカイブ。
- ^ 「モックとスタブの違いは何ですか?」Stack Overflow。 2022年7月4日時点のオリジナルよりアーカイブ。
- ^ 「フェイク、モッキング、スタブの違いは何ですか?」
- ^ Feathers, Michael (2005)。「センシングと分離」。レガシーコードでの効果的な作業。NJ: Prentice Hall。p. 23 以降。ISBN 0-13-117705-2。
- ^ Osherove, Roy (2009). 「モックオブジェクトを使用 したインタラクションテストなど」。ユニットテストの技法。Manning。ISBN 978-1-933988-27-6。
- ^これらの例では、 統一モデリング言語で使用される命名法に似た命名法が使用されています。
- ^ ab Beck, Kent (2003). Test-Driven Development By Example . ボストン: Addison Wesley. ISBN 0-321-14653-0。
- ^ InJava.com のモッキング | O'Reilly Media
外部リンク
- Tim Mackinnon (2009 年 9 月 8 日). 「A Brief History of Mock Objects」. Mockobjects.com/. 2023 年 6 月 7 日時点のオリジナルよりアーカイブ。
- テストダブル: ユニットテストパターンに関する書籍のセクション。
- モックオブジェクトについてすべて!モックオブジェクトに関するポータル
- 「複雑な単体テストにモック オブジェクトを使用する」。IBM developerWorks。2006 年 10 月 16 日。2007 年 5 月 4 日時点のオリジナルからアーカイブ。
- モックオブジェクトを使用したユニットテスト IBM developerWorks
- モックはスタブではありません ( Martin Fowler ) モック オブジェクトを使用したテストの開発に関する記事。「古典的な」テストと「モック主義的な」テストの流派を識別して比較します。設計と保守への影響に関する点についても触れています。
