23

最初にモックを紹介されたとき、主な目的は外部データ ソースからのオブジェクトをモックアップすることだと感じました。この方法では、自動化された単体テストのテスト データベースを維持する必要はなく、単にそれを偽造することができました。

しかし、今は違うことを考え始めています。テストされたメソッドをそれ自体の外部から完全に分離するためにモックを使用する方が効果的かどうか疑問に思っています。頭に浮かび続けるイメージは、絵を描くときに使う背景です。ペンキが全体に行き渡るのを防ぎたいのです。私はその方法をテストしているだけで、これらの偽造された外部要因にどのように反応するかを知りたいだけですか?

このようにするのは信じられないほど面倒に思えますが、私が見ている利点は、テストが失敗した場合、それは 16 層下ではなく、めちゃくちゃになっているためです。しかし、今では同じテスト範囲を得るために 16 のテストを行う必要があります。さらに、各テストはより複雑になり、テスト対象のメソッドとより深く結びついています。

私には正しいと思いますが、残忍にも見えるので、他の人がどう思うか知りたいです.

4

9 に答える 9

19

私が提供できるよりも信頼できるモックの扱いについては、Martin Fowler の記事「モックはスタブではありません」を参照することをお勧めします。

モックの目的は、依存関係を分離してコードを単体テストし、「単体」レベルでコードの一部を真にテストできるようにすることです。テスト対象のコードは本物であり、(パラメータや依存性注入などを介して) 依存する他のすべてのコードは「モック」(メソッドの 1 つが呼び出されたときに常に期待値を返す空の実装) です。

モックは最初は面倒に思えるかもしれませんが、慣れると、単体テストがはるかに簡単になり、堅牢になります。ほとんどの言語には、モックを比較的簡単にするモック ライブラリがあります。Java を使用している場合は、個人的にお気に入りのEasyMock をお勧めします。

最後に、統合テストも必要ですが、十分な量の単体テストがあると、バグが存在する場合、どのコンポーネントにバグが含まれているかを見つけるのに役立ちます。

于 2008-09-12T15:20:04.260 に答える
15

ルーク様、暗い道を行くな。:) すべてを嘲笑しないでください。できますが、すべきではありません...理由は次のとおりです。

  • 各メソッドを個別にテストし続けると、ビッグバンのようにすべてをまとめたときに驚きと作業が必要になります。私たちはオブジェクトを構築して、より大きな問題を解決するために連携できるようにします。それ自体では重要ではありません。すべての共同作業者が期待どおりに機能しているかどうかを知る必要があります。
  • モックは重複を導入することでテストを脆くします - はい、それは憂慮すべきことだと思います。セットアップを期待するすべてのモックについて、メソッド シグネチャが存在する場所が n 個あります。実際のコードとモックの期待 (複数のテストで)。実際のコードを変更する方が簡単です...すべてのモックの期待値を更新するのは面倒です。
  • あなたのテストは、インサイダーの実装情報を知ることができます。したがって、テストは、ソリューションの実装方法に依存します...悪いです。テストは、複数のソリューションで満たすことができる独立した仕様である必要があります。テスト スイートを書き直すことなく、コード ブロックで削除を押して再実装する自由が必要です。要件は同じままです。

最後に、「アヒルのように鳴き、アヒルのように歩くなら、それはおそらくアヒルだ」と言うでしょう。*モックを使用して、IO 操作、データベース、サード パーティ コンポーネントなどの問題のある子を抽象化します。ソルトのように、必要なものもいくつかあります。多すぎて :x *
これは、状態ベースのテストと反復ベースのテストの聖戦です。 ..ググると、より深い洞察が得られます。

明確化:私はここで統合テストに関するいくつかの抵抗を打っています:)だから、私の立場を明確にするために..

  • モックは「受け入れテスト」/統合領域には含まれません。それらは単体テストの世界でのみ見つけることができます..そしてそれが私の焦点です。
  • 受け入れテストは異なり、非常に必要とされています - それらを軽視することはありません。ただし、単体テストと受け入れテストは異なるものであり、別々に保つ必要があります。
  • コンポーネントまたはパッケージ内のすべての共同作業者は、互いに分離する必要はありません..オーバーキルであるマイクロ最適化のように. それらは一緒に問題を解決するために存在します..結束。
于 2008-09-12T15:14:28.717 に答える
2

はい私は同意する。モッキングは時に苦痛を伴いますが、多くの場合、テストが真に単体テストになるために必要です。つまり、テストに関与できる最小単位のみがテスト対象になります。これにより、テストの結果に影響を与える可能性のある他の要因を排除できます。最終的にはより多くの小さなテストを行うことになりますが、コードのどこに問題があるかを突き止めるのは非常に簡単になります。

于 2008-09-12T15:05:10.520 に答える
1

はい、それはモックでテストすることの欠点です。残酷な感じがするので、あなたが投入しなければならない仕事はたくさんあります。しかし、それが単体テストの本質です。外部リソースをモックしない場合、どうすれば単独で何かをテストできますか?

一方、遅い機能(データベースやI / O操作など)をモックアウトしていることになります。テストがより速く実行される場合、それはプログラマーを幸せに保つでしょう。1つの機能を実装しようとしているときに、実行が完了するまでに10秒以上かかる、非常に遅いテストを待つことほど苦痛なことはありません。

プロジェクト内のすべての開発者が単体テストの作成に時間を費やした場合、それらの16層(間接参照)はそれほど問題にはなりません。うまくいけば、最初からそのテストカバレッジが必要ですよね?:)

また、共同でオブジェクト間の機能/統合テストを作成することを忘れないでください。そうでなければ、何かを見逃す可能性があります。これらのテストは頻繁に実行する必要はありませんが、それでも重要です。

于 2008-09-12T15:27:16.877 に答える
1

モックは、次の質問に答えるために部分的に発明されました。ゲッターやセッターがない場合、テストオブジェクトをどのように単体テストしますか?

最近では、オブジェクトではなくロールをモックすることをお勧めします。「スマートスタブ」としてではなく、コラボレーションと責任の分離について話すための設計ツールとしてモックを使用します。

于 2008-10-18T14:40:36.953 に答える
1

誰かが前に言ったように、テストしているクラスよりも細かく分離するためにすべてをモックする場合、テスト中のコードに結束を強制することを断念します。

モッキングには、振る舞いの検証という基本的な利点があることに注意してください。これはスタブでは提供されないものであり、テストを脆弱にするもう 1 つの理由です (ただし、コード カバレッジは向上します)。

于 2008-09-23T15:39:11.380 に答える
1

私の哲学は、コードに合うようにテストを書くのではなく、テストに合うようにテスト可能なコードを書くべきだというもの
です。

複雑さに関しては、私の意見では、テストは簡単に書けるようにすべきだと思います。

モックしているクラスにテスト スイートがない場合は、適切なテスト スイートがあれば、分離せずに問題がどこにあるかがわかるため、それは良い考えであることに同意するかもしれません。

私がモックオブジェクトを使用した時間のほとんどは、テストを書いているコードが非常に密結合されている場合 (読み: 悪い設計) であり、依存するクラスが利用できない場合にモックオブジェクトを作成する必要があります。確かにモック オブジェクトには有効な用途がありますが、コードでそれらを使用する必要がある場合は、設計をもう一度検討します。

于 2008-09-12T15:17:16.433 に答える
1

確かに、モックは、データベースや Web サービスなどの外部データ ソースをシミュレートするために使用することを目的としています。しかし、より細かいスケールでは、疎結合コードを設計している場合は、「外部システム」である可能性があるものについて、コード全体にほぼ任意に線を引くことができます。私が現在取り組んでいるプロジェクトを取り上げます。

誰かがチェックインを試みると、CheckInUiはCheckInInfoオブジェクトをCheckInMediatorオブジェクトに送信し、CheckInValidatorを使用してそれを検証し、問題がなければ、 CheckInInfoAdapterを使用してTransactionという名前のドメイン オブジェクトに CheckInInfo を入力し、そのTransactionITransactionDaoのインスタンスに渡します。永続化のための.SaveTransaction()

私は現在、いくつかの自動化された統合テストを書いています。明らかに、CheckInUiITransactionDaoは外部システムへのウィンドウであり、モックする必要があります。しかし、ある時点でCheckInValidatorが Web サービスを呼び出さなくなると誰が言えるでしょうか? そのため、単体テストを作成するときに、クラスの特定の機能以外はすべて外部システムであると想定します。したがって、CheckInMediatorの単体テストでは、対話するすべてのオブジェクトをモックアウトします。

編集: Gishu は技術的に正しいです。すべてをモックする必要はありません。たとえば、CheckInInfoは単にデータのコンテナーであるため、モックしません。ただし、外部サービスとして表示される可能性のあるもの (および、データを変換したり、副作用を持つほとんどすべてのもの) はモックする必要があります。

私が好きな類推は、適切に疎結合された設計を、その周りに立ってキャッチゲームをしている人々のフィールドと考えることです。誰かがボールを渡されたとき、彼は次の人にまったく異なるボールを投げたり、別の人に連続して複数のボールを投げたり、ボールを投げてボールを受け取ってから別の人に投げたりすることさえあります. 不思議なゲームです。

コーチおよびマネージャーとして、チームの練習 (統合テスト) を行うためにチーム全体がどのように機能するかを確認したいのはもちろんですが、バックストップとボール ピッチング マシンに対して各プレーヤーが個別に練習することも必要です (ユニット テスト)。モック)。この写真に欠けている唯一の部分は、モックの期待です。そのため、ボールが当たったときにバックストップを汚すように、ボールに黒いタールを塗っています。各バックストップには、その人が狙っている「ターゲットエリア」があり、練習走行の終わりにターゲットエリア内に黒いマークがない場合は、何かが間違っていて、その人がテクニックを調整する必要があることがわかります.

本当に時間をかけて正しく学習してください。Mocks を理解した日は、本当に驚きの瞬間でした。コントロール コンテナーの反転と組み合わせると、もう後戻りできません。

余談ですが、IT 担当者の 1 人がやってきて、無料のラップトップをくれました。

于 2008-09-12T15:43:34.310 に答える
0

モック オブジェクトは、1) テスト対象のコードを分離する手段としてよく使用されますが、2) keithb が既に指摘したように、「共同作業するオブジェクト間の関係に注目する」ために重要です。この記事では、テーマに関連するいくつかの洞察と歴史を提供します:モック オブジェクトを使用した責任主導の設計

于 2010-07-18T16:27:15.887 に答える