モックフレームワークとMS Fakesフレームワーク


99

NMockとVS 2011 Fakes FrameworkのようなMockフレームワークの違いについて少し混乱しています。MSDNを通して、FakesはRhinoMockやNMockのように依存関係を模擬できることを理解していますが、アプローチは異なります。Fakesはこの機能を実現するコードを生成しますが、Mocksフレームワークはそうではありません。それで私の理解は正しいですか?偽物は単なる別のモックフレームワークですか

回答:


189

あなたの質問は、MS FakesフレームワークがNMockとどのように異なるかについてでした。他の回答でその一部が解決されたようですが、それらが同じである点と異なる点について、さらに詳しく説明します。NMockはRhinoMocksとMoqにも似ているため、NMockでグループ化しています。

NMock / RhinoMocks / MoqとMS Fakes Frameworkの間には、3つの大きな違いがあります。

  • MSの偽造フレームワークは、ジェネリック型ではなく、以前のバージョンのVisual Studioのアクセサーと同様に、生成されたコードを使用します。依存関係に偽のフレームワークを使用する場合は、依存関係を含むアセンブリをテストプロジェクトの参照に追加し、それを右クリックしてテストダブル(スタブまたはシム)を生成します。次に、テストするとき、実際にはこれらの生成されたクラスを代わりに使用しています。NMockはジェネリックを使用して同じことを実行します(つまりIStudentRepository studentRepository = mocks.NewMock<IStudentRepository>())。私の意見では、MS Fakesフレームワークアプローチは、実際のインターフェイスではなく生成されたクラスに対して実際に作業しているため、テスト内からのコードナビゲーションとリファクタリングを禁止します。

  • MS fakesフレームワークはスタブとモル(シム)を提供しますが、NMock、RhinoMocks、およびMoqはすべてスタブとモックを提供ます。私はモックを含めないというMSの決定を本当に理解していません。私は個人的に、以下に説明する理由により、モグラのファンではありません。

  • MS fakesフレームワークでは、スタブしたいメソッドの代替実装を提供します。これらの代替実装では、戻り値を指定し、メソッドが呼び出された方法または呼び出されたかどうかに関する情報を追跡できます。NMock、RhinoMocks、およびMoqでは、モックオブジェクトを生成し、そのオブジェクトを使用して、スタブ化された戻り値を指定したり、相互作用(メソッドが呼び出されたかどうか、どのように呼び出されたか)を追跡したりします。MSの偽造品のアプローチはより複雑で表現力に欠けると思います。

フレームワークが提供するものの違いを明確にするために、NMock、RhinoMocks、およびMoqはすべて、2種類のテストダブル(スタブとモック)を提供します。偽のフレームワークはスタブとモル(それらはシムと呼ばれます)を提供しますが、残念ながらモックは含まれていません。NMockとMS Fakesの違いと類似点を理解するには、これらの異なるタイプのテストdoubleが何であるかを理解することが役立ちます。

スタブ:スタブは、テスト対象のメソッドによってテストdoubleが要求されるメソッドまたはプロパティの値を提供する必要がある場合に使用されます。たとえば、テスト対象のメソッドがIStudentRepositoryテストdoubleのDoesStudentExist()メソッドを呼び出すと、trueが返されます。

NMockとMSフェイクのスタブの考え方は同じですが、NMockでは次のようにします。

Stub.On(mockStudentRepository).Method("DoesStudentExist").Will(Return.Value(true));

そして、MSFakesを使用すると、次のようになんとかすることができます。

IStudentRepository studentRepository = new DataAccess.Fakes.StubIStudentRepository() // Generated by Fakes.
{
    DoesStudentExistInt32 = (studentId) => { return new Student(); }
};

MS Fakesの例では、DoesStudentExistメソッドのまったく新しい実装を作成していることに注意してください(DosStudentExistInt32と呼ばれることに注意してください。これは、Fakesフレームワークがスタブオブジェクトを生成するときにメソッド名にパラメーターデータ型を追加するためです。これにより、テスト)。正直に言うと、NMock実装は文字列を使用してメソッド名を識別するため、バグが発生します。(NMockの使用方法を誤解している場合はご容赦ください。)このアプローチはリファクタリングを本当に阻害するため、この理由から、NMockよりもRhinoMocksまたはMoqを強くお勧めします。

モック:モックは、テスト中のメソッドとその依存関係の間の相互作用を検証するために使用されます。NMockでは、次のように期待値を設定してこれを行います。

Expect.Once.On(mockStudentRepository).Method("Find").With(123);

これは、私がNMockよりもRhinoMocksとMoqを好むもう1つの理由です。NMockは古い期待スタイルを使用しますが、RhinoMocksとMoqはどちらも、このようなテストの最後にアサーションとして期待される相互作用を指定するArrange / Act / Assertアプローチをサポートします。 :

stubStudentRepository.AssertWasCalled( x => x.Find(123));

繰り返しますが、RhinoMocksはメソッドを識別するために文字列の代わりにラムダを使用しています。ms fakesフレームワークはモックをまったく提供しません。つまり、スタブ化された実装(上記のスタブの説明を参照)では、後で正しく設定されたことを確認する変数を設定する必要があります。これは次のようになります。

bool wasFindCalled = false;

IStudentRepository studentRepository = new DataAccess.Fakes.StubIStudentRepository() 
{
    DoesStudentExistInt32 = (studentId) => 
        { 
            wasFindCalled = true;
            return new Student(); 
        }
};

classUnderTest.MethodUnderTest();

Assert.IsTrue(wasFindCalled);

スタブで呼び出しを追跡し、テストの後半でそれをアサートする必要があるため、このアプローチは少し複雑です。NMock、特にRhinoMocksの例はより表現力があると思います。

ほくろ(シムズ):率直に言って、私はほくろが嫌いです。誤用の可能性があるからです。単体テスト(特にTDD)で私が非常に気に入っている点の1つは、コードをテストすると、不適切なコードをどこに記述したかを理解するのに役立つことです。これは、不十分に記述されたコードのテストが難しいためです。ほくろは実際には、注入されない依存関係に対してテストしたり、プライベートメソッドをテストしたりできるように設計されているため、ほくろを使用する場合は当てはまりません。これらは、次のようなShimsContextを使用することを除いて、スタブと同様に機能します。

using (ShimsContext.Create())
{
    System.Fakes.ShimDateTime.NowGet = () => { return new DateTime(fixedYear, 1, 1); };
}

シムに関する私の心配は、人々がそれらを「ユニットテストへのより簡単な方法」と見なし始めることです。この概念の詳細については、私の投稿を参照してください。

偽のフレームワークに関連するいくつかの懸念の詳細については、以下の投稿をご覧ください。

RhinoMocksの学習に興味がある場合は、Pluralsightトレーニングビデオをご覧ください(完全な開示-このコースを書いて視聴料を支払うことができましたが、このディスカッションにも当てはまると思うので、ここに含めます)。


14
@ジム「注入されない依存関係に対してテストする」ことを許可することは悪いことだと私は同意しません。それどころか、実際には、この機能は、無意味なインターフェースと関連する「オブジェクト配線」構成/複雑さの多いコードベースが雑然とするのを防ぐのに役立ちます。私はすでにいくつかのプロジェクト(Javaと.NETの両方)を見てきましたが、それらは単一の実装クラスだけで何百ものJava / C#インターフェースを持ち、多くの役に立たないXML構成(Spring DI Beanの場合、またはMS UnityのWeb.configで)フレームワーク)。このような依存関係は注入されない方がよいでしょう。
ホジェリオ

19
@Rogerio、私はこのモデルに従う何千ものクラスを持つ複数のプロジェクトに取り組んでおり、依存性注入が正しく行われている場合(XML構成を使用している場合、正しく行われていない場合は、imho)、それは単純で比較的痛みがありません。一方、私はこれを行わないシステムで作業してきましたが、クラス間の結合は常に私に大きな苦痛を引き起こしました。テストは、依存性注入を使用する理由ではありません(悪い理由ではありません)。本当の理由は、緩んだカップリングです。単一のクラスによって実装されるインターフェースを持つことは、私に痛みを引き起こしたことはありません。
ジムクーパー

17
@ジム、私は悪いデザインをテストする能力は素晴らしいプラスだと思います。レガシーコードをより良いデザインにリファクタリングする前に最初にしたいことは、テストを書くことです。
Thomas Materna 2013年

4
私のルールは、インターフェイスを実装するためにアクセスできない共有/静的メソッドまたはクラスをShimする必要がある場合にのみ、Fakesを使用することです。それ以外はすべてMoqを使用します。フェイクは遅くなり(フェイクアセンブリを生成する必要があるため)、Moqで取得する機能と一致させるには、より多くのコーディング作業が必要です。
Nick

5
@ CarloV.Dangoまず第一に、Dependency Injectionが個別のインターフェースを必要としないことを私は完全に知っています。私の以前のコメントは、DIを使用するときにそのようなインターフェースを作成する傾向をほのめかしただけでした。次に、「IOC」(制御の反転)はDIとは関係ありません。(1つ目はメソッド間の制御フローの反転に関するもので、2つ目はコンポーネント/オブジェクトの依存関係の解決に関するものです。)IOCとDIを混同することで、私ではなく無知を示しているのはあなたです。そして、率直に言って、このサイトは他の人を侮辱するに値しないので、どうかそれを市民にしておこう。
ホジェリオ

23

あなたは正しいですが、物語にはまだまだあります。この答えから取り除く最も重要なことは次のとおりです。

  1. アーキテクチャは、フェイクやモックの松葉杖に頼るのではなく、スタブと依存性注入を適切に使用する必要があります

  2. 偽物やモックは、次のような変更すべきでない、または変更できないコードをテストするのに役立ちます。

    • スタブを使用しない(または効率的に使用する)レガシーコード
    • サードパーティのAPI
    • ソースコードがないリソース

Shims(開発中は「Moles」と呼ばれます)は、実際には迂回呼び出しによって動作するモックフレームワークです。モックを手間をかけて構築する代わりに(そうです、Moqを使用するのも比較的苦痛です!)、shimは単に既存の本番コードオブジェクトを使用するだけです。Shimsは、呼び出しを本番ターゲットからテストデリゲートに再ルーティングするだけです。

スタブは、ターゲットプロジェクトのインターフェイスから生成されます。Stubオブジェクトはそれだけです-インターフェースの実装です。スタブタイプを使用する利点は、作成に時間を浪費することは言うまでもなく、多くの使い捨てスタブでテストプロジェクトを混乱させることなく、スタブをすばやく生成できることです。もちろん、多くのテストで使用するために、具体的なスタブを作成する必要があります。

Fakes(Shim、Mocks、Stubタイプ)を効率的に実装するには少し慣れますが、努力する価値は十分にあります。Shims / Mole、Mocks、およびStubタイプを使用することで、開発時間を数週間節約できました。私が持っているのと同じくらいあなたが技術を楽しんでくれることを願っています!


11
仕様の欠如と、Fakesに関するコメントの用語の問題に基づいて反対票を投じました。偽物はすべてのタイプのテストダブルの総称であり、偽物のライブラリに使用されたMSの名前でもあります。彼らのライブラリーでは、シムだけが実際にはモールであり、スタブはそうではありません。例の必要性に関して、Fakesを使用したシム(またはスタブ)の作成がMoqを使用するよりも簡単であることを示す回答の例を参照してください。これらを解決するために回答を変更した場合、私は反対票を変更します。
ジムクーパー

1
しかし、シム(モル)、つまりサードパーティのコード、システム/ SDK APIを使用するための正当な理由を追加します。自社のソリューションを使用しているときだけではありません。それで私はあなたにそれを均等にするためにあなたに一票を投じます:-)
トニーウォール

2
@Mike and Jim ..この回答で使用されている用語を修正するために努力しました。改善できるかどうかお知らせください。ありがとう。
Snesh 2014

15

私が理解しているように、Visual Studioチームは、.NETで利用できるさまざまなモックライブラリとの競合を避けたいと考えていました。MSはこのような難しい決断に直面することがよくあります。特定の機能を提供しない場合( "MSがモックライブラリを提供しない理由。モックがそのような一般的な要件である理由は何ですか?")自然な支持者は市場に出ていないのですか?」それはここに当てはまるようです。

フェイクのシム機能は本当に、本当に便利です。もちろん、危険はあります。必要な場合にのみこれを使用するようにするには、ある程度の規則が必要です。しかし、それは大きなギャップを埋めます。私の主な不満は、VS 2012のUltimateエディションでのみ提供されるため、.NET開発コミュニティのサブセクションでのみ利用できることです。お気の毒に。


2
fakesフレームワークはPremiumエディションでも利用できます。
AlwaysAProgrammer 2014年

13

偽物には2種類の「偽物」オブジェクトが含まれています。最初のものは「スタブ」と呼ばれ、本質的に自動生成されたダミーであり、そのデフォルトの動作をオーバーライドして(通常はオーバーライドして)より興味深いモックにすることができます。ただし、現在利用可能なモックフレームワークのほとんどが提供する機能の一部が不足しています。たとえば、スタブインスタンスのメソッドが呼び出されたことを確認する場合は、このロジックを自分で追加する必要があります。基本的に、自分でモックを手動で作成している場合、スタブはおそらく改善のように思えます。ただし、すでにフル機能のモックフレームワークを使用している場合は、Fakesスタブから欠落している重要な部分があるように感じるかもしれません。

「シム」と呼ばれる、Fakesによって提供されるオブジェクトのもう1つのカテゴリは、モックを介した標準の置き換えでは適切に分離されていない(またはできない)依存関係の動作を置き換えるメカニズムを公開します。私の知る限り、TypeMockは、現在この種の機能を提供している主要なモックフレームワークの1つだけです。

ところで、もしあなたが以前にMolesを試したことがあるなら、Fakesは本質的に同じものであり、ついにMicrosoft Researchから出て実際の製品になった。


1
更新:MolesがMS Fakesに統合されました。「Visual Studio 2012のFakesフレームワークは次世代のMoles&Stubsです。ただし、FakesはMolesとは異なるため、MolesからFakesに移行するにはコードを変更する必要があります。MolesフレームワークはVisual Studio 2012ではサポートされません。 」出典:research.microsoft.com/en-us/projects/moles
Sire

1

Fake(Shim + Stub)オブジェクトに関しては、上記で十分に定義されていますが、最後のコメントの最後の段落では、状況全体がかなりよくまとめられていると思います。

多くの人々は、一部のユニットテストケースではFake(Shim + Stub)オブジェクトが適切な資産であると主張しますが、欠点は、Visual Studio 2012またはVisual Studio 2013を使用している場合でも、これらのオプションのみが利用可能であることです。プレミアムまたはアルティメットバージョン。IOW、これは、Proバージョンでこれらの偽物(Shim + Stub)を実行する必要がないことを意味します。

おそらくProバージョンでは[Fakes(Shim + Stub)]メニューオプションが表示されるかもしれませんが、まったく何もない状態になる可能性がかなりあります。重要なことを伝えるコンパイルエラーは生成されません。不足している、オプションがそこにないだけなので、時間を無駄にしないでください...

開発チームで検討することは重要な要素です。特にUltimateバージョンを使用している人が1人だけで、他の人がProバージョンを使用している場合は特に重要です。一方、Moqは、使用するVisual Studioバージョンに関係なく、Nugetを介して簡単にインストールできます。Moqを使用しても問題はありませんでした。どのツールの場合も、キーの用途と使用方法を理解することが重要です;)


1
質問を読みやすくするために、小さな段落にフォーマットしてください。

@SirXamelot、コードをリファクタリングしない場合、.NET提供の静的呼び出しの出力を変更することはできません。例:DateTime.NowまたはGuid.NewGuid
zaitsman
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.