web-dev-qa-db-ja.com

所有しているタイプのみをモックする必要がありますか?

私は読み通しました TDD:あなたが所有するモックタイプのみ Mark Needhamによるエントリであり、これがベストプラクティスであるかどうかを知りたいですか?

彼はモックに反対しているのではなく、直接モックに反対していることに注意してください。ラッパーを作成してモックするのは問題ないと言っています。

42
Oded

モックかモック™かによって異なります…

モックフレームワーク(Mockitoなど)を使用してスタブを作成している場合、所有していないタイプのスタブを作成することはまったく問題なく、合理的です。

ただし、モックフレームワーク(Mockitoなど)を使用してmock™オブジェクトを作成している場合は、文字通りmock™エバンジェリストのアドバイスに従うのが最善です。個人的に私はその動きに触れなくなったので、マーク・ニーダムのアドバイスがコーシャと見なされるかどうかはわかりません。

皮肉なことに、MarkがHibernateでのEntityManagersのモックについて書いていること自体は、合理的に聞こえます。しかし、その特定のケースから、「所有していないタイプをモックしない」などのルールを一般化できるとは思えません。意味がある場合もあれば、意味がない場合もあります。

25
akuhn

私の答えは「いいえ」です。特定の単体テストのコンテキストで意味のあるものはすべてモックする必要があります。モックタイプを「所有」しているかどうかは関係ありません。

最近、Javaまたは.NET環境では、すべて(そして私は本当にすべてを意味します)を簡単にモックすることができます。したがって、最初に追加のラッパーコードを書く手間をかける技術的な理由はありません。 。


私が最近(2010年11月)考えていたいくつかの追加のアイデアは、「あなたが所有するモックタイプのみ」がいかに非論理的であるかを示しています。

  1. doサードパーティAPIのラッパーを作成し、単体テストでラッパーをモックするとします。ただし、後でラッパーを別のアプリで再利用できることがわかったので、ラッパーを別のライブラリに移動します。そのため、ラッパーはユーザーによって「所有」されなくなりました(複数のアプリで使用され、異なるチームによって維持される可能性があるため)。開発者は古いラッパーの新しいラッパーを作成する必要がありますか?!?そして、本質的に役に立たないコードのレイヤーを重ねて、再帰的にそれを続けますか?
  2. 他の誰かがすでにいくつかの重要なAPIのNiceラッパーを作成し、それを再利用可能なライブラリとして利用できるようにしたとします。上記のラッパーが特定のユースケースに必要なものである場合、最初にラッパーのラッパーをほぼ同じAPIで作成する必要があります。そうすれば、それを「所有」することができますか?!?

具体的で現実的な例として、Apache Commons EmailAPIを考えてみましょう。これは標準のJava Mail APIのラッパーにすぎません。私はそれを所有していないので、常に作成する必要があります。 Commons Email APIのラッパー、電子メールを送信する必要があるクラスのユニットテストを作成するときはいつでも?

32
Rogério

私は Mockitoプロジェクトが与える説明 この質問が好きです。

所有していないタイプをモックしないでください!

これは難しい線ではありませんが、この線を越えると影響が出る可能性があります。 (おそらくそうなるでしょう)

  1. サードパーティのライブラリをあざけるコードを想像してみてください。 3番目のライブラリを特定にアップグレードした後、ロジックが少し変更される可能性がありますが、テストスイートはモックされているため、正常に実行されます。後で、すべてが順調に進んでいると考えて、ビルドウォールは結局緑であり、ソフトウェアが展開されて...ブーム
  2. 現在の設計がこのサードパーティライブラリから十分に分離されていないことを示している可能性があります。
  3. また、別の問題は、サードパーティのライブラリが複雑で、正しく機能するために多くのモックを必要とする可能性があることです。それは過度に指定されたテストと複雑なフィクスチャにつながり、それ自体がコンパクトで読みやすい目標を損ないます。または、外部システムをモックするのが複雑なため、コードを十分にカバーしていないテストに。

代わりに、最も一般的な方法は、外部lib/systemの周りにラッパーを作成することですが、低レベルのAPI、概念、または例外が多すぎると、ラッパーの境界を超えてしまう抽象化リークのリスクに注意する必要があります。サードパーティライブラリとの統合を検証するために、統合テストを作成し、それらを可能な限りコンパクトで読みやすくします。

15
H6.

「いいえ」と言うつもりでしたが、ブログの投稿をざっと見てみると、彼が何をしているのかがわかります。

彼は特にHibernateでEntityManagerをモックすることについて話します。私はこれに反対です。 EntityManagerはDAO(または同様のもの)内に非表示にする必要があり、DAOはモックする必要があります。 EntityManagerへの1行の呼び出しをテストすることは、時間の無駄であり、何かが変更されるとすぐに中断します。

ただし、サードパーティのコードを使用している場合は、それとの対話方法をテストする必要があります。

9
cletus

私見、所有権の問題は関係ありません。

関連する質問は、カップリングの質問です。つまり、テストコードで何が指定されていますか。たまたま使用するライブラリのAPIの詳細を指定するテストコードは必要ありません。これは、たとえば次の場合に得られるものです。 Mockitoを使用して、テストクラスでライブラリを直接モックします。

広範なソリューションの提案 この問題の場合は、ライブラリの周りにラッパーを作成してから、ラッパーをモックすることです。ただし、これには次の欠点があります。

  • ラッパー内のコードはテストされていません。
  • ラッパーは不完全な抽象化である可能性があるため、ラッパーのAPIを変更する必要がある場合があります。多くのテストでラッパーをモックした場合は、これらすべてのテストを適応させる必要があります。

したがって、代わりに、生産的なコードのインターフェイスからテストを分離することをお勧めします。モックをテストコードに直接配置するのではなく、生産的なインターフェイスを実装またはモックする別のスタブクラスを作成します。次に、テストが必要なセットアップまたはアサーションを実行できるようにする2番目のインターフェイスをスタブに追加します。そうすれば、生産的なインターフェースが変更された場合に備えて、1つのクラスを適応させるだけで済みます。複雑な、または頻繁に変更されるライブラリのインターフェースをモック/スタブする余裕さえあります。


注:これはすべて、モックまたはスタブを実際に使用する必要があることを前提としています。この質問はOPの質問の範囲外だったため、ここでは説明しませんでした。しかし、実際にはモック/スタブを使用する必要があるかどうかを自問してください。私の経験では、それらは酷使されています...

2
oberlies

私はマークが言っていることに同意します。残念ながら、すべてをモックすることはできません。通常の使用がブラックボックスであるという理由だけで、モックしたくないものがあります。

私の経験則は、テストを高速にするが、テストを不安定にすることのないモックです。すべての偽物が同じであるとは限らないことを忘れないでください モックはスタブではありません

0
AutomatedTester

私は確かに少数派ですが、モックをコードの臭いと見なし、可能であれば代わりに依存性注入を使用します。理論的根拠は、モックは基本的に、テストが難しいコードをテストするための回避策であるということです。モックは、特定のバージョンのライブラリのように(せいぜい)動作するため、テストを弱めます。ライブラリが変更された場合、テストはチェック値をすべて失います。

上記を読むと、私がMark Needham自身の引数を使用していることがわかりますが、所有していないオブジェクトをモックするべきではないが、モックするべきではないと言っているわけではありません...

OK、依存性注入がオプションでない場合は、モックを作成しましょう...しかし、テストは偽物であり、本番コードのようには動作しないことを理解する必要があります。これは実際の単体テストではなく、部分的に偽造されたものです。可能であれば、モックオブジェクトの動作が期待どおりであることを確認するテストを追加することで、それを減らすことができます。

0
kriss