質問

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

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

この方法で実行するのは信じられないほど面倒に思えますが、私が感じている利点は、テストが失敗した場合、それは 16 層ダウンしているのではなく、失敗しているためであるということです。しかし、各部分が個別にテストされるため、同じテスト範囲を取得するには 16 回のテストが必要になります。さらに、各テストはより複雑になり、テスト対象のメソッドとより深く結びつきます。

それは私にとって正しいと感じますが、残酷にも見えるので、他の人がどう思うか知りたいと思っています。

役に立ちましたか?

解決

Martin Fowler の記事を参照することをお勧めします。 モックはスタブではない 私ができる以上にモックを権威ある扱いにしてくれます。

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

モックは最初は退屈に思えるかもしれませんが、使い方のコツを掴めば、単体テストがはるかに簡単かつ堅牢になります。ほとんどの言語にはモック ライブラリがあり、モックを比較的簡単に作成できます。Java を使用している場合は、私の個人的なお気に入りをお勧めします。 イージーモック。

最後にこの考えを述べさせてください。統合テストも必要ですが、単体テストを十分に行うと、バグが存在する場合に、どのコンポーネントにバグが含まれているかを見つけるのに役立ちます。

他のヒント

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

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

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

説明:ちょっと抵抗がありますが、ここで統合テスト:) 私の立場を明確にするために..

  • モックは、「受け入れテスト」/統合領域には含まれません。これらは単体テストの世界でのみ見つかります。それが私のここでの焦点です。
  • 受け入れテストは異なります。 とても 必要だった - 彼らを軽視しているわけではない。ただし、単体テストと受け入れテストは異なるものであり、異なるものにしておく必要があります。
  • コンポーネントまたはパッケージ内のすべてのコラボレーターを相互に分離する必要はありません。過剰なマイクロ最適化と同様です。彼らは問題を解決するために存在します 一緒に..凝集。

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

私の哲学は、テストに適合するテスト可能なコードを作成する必要があるということです。
コードに適合するテストを書かないでください。

複雑さに関して言えば、私の意見は、テストは簡単に書けるべきだということです。単純に複雑であれば、より多くのテストを書く必要があるからです。

モックしているクラスにテスト スイートがない場合は、それが良いアイデアになる可能性があることに私も同意するかもしれません。適切なテスト スイートがあれば、分離することなく問題がどこにあるのかがわかるからです。

私がモック オブジェクトを使用する機会のほとんどは、テストを作成しているコードが非常に緊密に結合されている場合です (以下を読んでください)。悪い設計)、依​​存するクラスが利用できない場合にモックオブジェクトを作成する必要があります。確かにモックオブジェクトには有効な用途がありますが、コードが 必要 使い方を考えたら、デザインをもう一度検討してみます。

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

一方で、遅い機能 (データベースや I/O 操作など) を嘲笑していることになります。テストの実行速度が速ければ、プログラマは満足するでしょう。1 つの機能を実装しようとしているときに、実行が完了するまでに 10 秒以上かかる非常に遅いテストを待つことほど苦痛なことはありません。

プロジェクトの開発者全員が単体テストの作成に時間を費やした場合、(間接的な) 16 層はそれほど問題にはならないでしょう。願わくば、最初からそのテスト範囲を備えているべきですよね?:)

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

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

誰かがチェックインしようとすると、 チェックインUi を送信します チェックイン情報 に反対する チェックインメディエーター を使用して検証するオブジェクト チェックインバリデーター, 問題がなければ、という名前のドメイン オブジェクトを埋めます。 取引チェックイン情報 を使用して チェックイン情報アダプター 次に、を渡します 取引 のインスタンスに ITransactionDao.SaveTransaction() 持続性のために。

私は今、自動化されたものを書いています 統合テスト そして明らかに チェックインUi そして ITransactionDao これらは外部システムへのウィンドウであり、モックされるべきものです。しかし、ある時点で誰がそれを言うか チェックインバリデーター Web サービスを呼び出すつもりはありませんか?だからこそ、書くときは、 単体テスト クラスの特定の機能以外はすべて外部システムであると想定します。したがって、私の単体テストでは チェックインメディエーター 私はそれが通信するすべてのオブジェクトを嘲笑します。

編集: Gishu は技術的には正しいです。すべてを嘲笑する必要はありません。たとえば、私は嘲笑しません チェックイン情報 それは単なるデータのコンテナだからです。ただし、外部サービスとして認識できるものはすべて (データを変換したり副作用があるものはほとんどすべて) モックする必要があります。

私が気に入っている例えは、適切に疎結合されたデザインを、人々がその周りに立ってキャッチボールをしているフィールドとして考えることです。誰かがボールをパスされると、次の人にまったく異なるボールを投げたり、複数のボールを続けて別の人に投げたり、ボールを投げて戻ってくるのを待ってからさらに別の人に投げたりすることもあります。奇妙なゲームです。

さて、コーチやマネージャーとして、あなたはチーム全体がどのように機能するかをチェックしたいと考えています。そのため、チーム練習 (統合テスト) を行うだけでなく、各プレーヤーがバックストップやボールピッチングマシンを相手に自分で練習することもできます (単体テスト)。モック)。この写真に欠けている唯一の部分は、疑似期待です。そのため、ボールに黒いタールを塗って、ボールが当たったときにバックストップを汚すようにしました。各バックストップには、その人が目指す「ターゲットエリア」があり、練習走行の終わりにターゲットエリア内に黒いマークがなければ、何かが間違っており、その人はテクニックを調整する必要があることがわかります。

しっかりと時間をかけて学んでください。モックを理解した日は、本当にすごいと思った瞬間でした。これをコントロールコンテナの反転と組み合わせれば、もう元には戻れません。

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

前に誰かが言ったように、テストしているクラスよりも細かく分離するためにすべてをモックすると、テスト対象のコードに一貫性を持たせることを放棄することになります。

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

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

最近、 推奨 実践するのは、オブジェクトではなく役割を模擬することです。モックを「スマート スタブ」としてではなく、コラボレーションと責任の分離について話すためのデザイン ツールとして使用します。

モック オブジェクトは 1) テスト対象のコードを分離する手段としてよく使用されますが、2) keithb がすでに指摘したように、重要です。連携するオブジェクト間の関係に焦点を当てる」。この記事では、この主題に関連するいくつかの洞察と歴史を示します。 モックオブジェクトを使用した責任主導の設計.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top