私はこれを読んだ answer Ragzitsuによる同じ質問について。私はまだ物事を実装する方法をまだ混乱しています。誰かが実装の例を教えてもらえますか。
次のクラスがあります。
class Fizz : IFizz
{
}
class Buzz : IBuzz
{
}
class Bar : IBar
{
}
class Foo : IFoo
{
public Foo(IBar bar, IFizz fizz, IBuzz buzz)
{
//initialize etc.
}
//public methods
}
ここでコンストラクタを回避する実用的な方法は何ですか?私は次のようなことをしたい
var foo = new Mock<IFoo>();
言い換えれば、コードはアドバイスの後にどのように見えますか
The best thing to do would be right click on your class and choose Extract interface.
以下に示すように、MockBehaviorを参照することにより、コンストラクターにパラメーター引数があるモックを作成できます。
Mock<testClass>(MockBehavior.Strict, new object[] {"Hello"});
あなたが本当に何をしようとしているのかは不明です。
インターフェイスIFoo
(これはあなたの質問が示すようです)をすでに定義しており、それを別のタイプにモックする必要がある場合は、すでに設定されています:var bazz = new Bazz(new Mock<IFoo>());
依存関係として別の型に提供する必要があるインターフェイスに抽象化していない具体的なクラスFoo
がある場合、インターフェイスを抽出することは、Bazz
オブジェクトを作成せずに初期化できる最も一般的な方法の1つです。実際のFoo
クラス。実際のコードがどのように見えるかに応じて、IFoo
が依存するFoo
の部分のみをBazz
に抽象化することにより、スコープを制限できます。もう1つの方法は、コンクリートをモックし、使用する コンストラクター引数 をmoqに提供することです。セットアップとリセットをモックに提供するために、Foo
の依存関係部分が「モック可能」(パブリック仮想)であることを確認する必要があります。
実際の質問に答えるための編集として
コードはアドバイスの後にどのように見えますか?最善のことは...インターフェイスを抽出することです?
インターフェイスを抽出するためのアドバイスは、探しているものとは異なる場合があります。他の回答で述べたように、私たちは実際にテストしようとしているものが何かわからないです。
テストする場合具体的な機能Foo
のIFoo
実装インターフェースの抽出とIFoo
のモックは、moqがインターフェース自体を実装するため、実際には役に立ちませんそして、その実装のセットアップメソッドとプロパティで提供するように指示した「機能」のみを提供します。これがあなたがしていることである場合、[〜#〜] and [〜#〜]テスト中のメソッドは、具体的なFoo
実装で他のメソッドを呼び出します[〜#〜] and [〜#〜]このメソッドは抽象化を提供したいものです。@ Chris Marisicが述べたように、抽象化するメソッドをvirtual
に変更します。これを仮想として、canは、モックフレームワークを使用して抽象化を提供するか、過去に行ったようにテストクラスのテスト対象からサブタイプを作成します。
_public class MyFooTests
{
... // Tests
private class SubFoo : Foo
{
public override void MethodToAbstract(bool par)
{
// do something expected
}
}
}
_
このメソッドを使用すると、Fooのコンストラクターに何かを提供する必要がありますが、それはこれらのインターフェイスでモックを使用する場合の主なケースです。
ここで、Foo
をテストしていて、テスト対象のメソッドがIBar
、IFizz
、IBuzz
のメソッドを呼び出しているだけで、他に作成したい抽象化がない場合は、すでにセットアップされています。これらのインターフェイスをモックし、特定のテストケースで期待するものを返すように設定し、Foo
にモックオブジェクトを提供します。
抽出インターフェースのアドバイスは、@ Chris Marisicによると、テスト対象がFooに依存している場合に非常に役立ちます。ただし、この状況でインターフェイスを作成したくないという彼の感情は共有できません。それはあなたにもっと臭いがするものに依存します:モック機能を提供するためのインターフェースを作成するか、同じものを提供するために修飾子を変更します。モディファイヤを変更し、moqを使用して具体的なFoo
をモックする場合は、デフォルトのコンストラクタを公開する(pretty smelly to me)か、指定されたコンストラクタ引数でモックを作成する必要がありますあなたの 参照された答え で述べられているように、仕様。
次のものがあるとしましょう:
_public class Baz
{
private Foo foo;
public Baz(Foo inputFoo)
{
this.foo = inputFoo;
}
public bool GetFromTheFoo()
{
// other stuff here
var fooStuff = this.foo.GetStuff();
// logic on the stuff;
return fooStuff != null;
}
}
_
上記のBaz
はFoo
に依存しています。 Foo
のインターフェースを抽出した後、Baz
はIFoo
を受け入れる必要があります。
すると、Foo
は質問のようになり、IFoo
は、Baz
から抽象化するメソッドのシグネチャ定義を持ちます。
_object GetStuff();
_
これで、テストでvar foo = new Mock<IFoo>();
を使用し、foo
をBaz
テストサブジェクトに指定できます。 IFoo.GetStuff()
メソッドをセットアップすることを忘れないでください。
_foo.Setup(f => f.GetStuff()).Returns(new object());
_
IFoo
抽象化を作成したため、必要はありません。
ここでコンストラクタを回避しますか?
IFoo
のモックには、moqが提供するデフォルトのコンストラクターのみがあるためです。
個人的には、IFizz
、IBuzz
、およびIBar
をBaz
の依存関係チェーンから削除するため、適用する場合はインターフェイスアプローチを好みます。 Baz
がFoo
に依存し、Foo
が_IFizz etc.
_に依存する場合、Baz
も_IFizz etc.
_に依存します。IFoo
を抽出した後、Baz
はIFoo
のみに依存します。
少し前にこれが尋ねられたので、これを追加する価値はないかもしれませんが、将来の読者のために、moqを使用するときは次のことは同じだと考えないでください。
_var fooDouble = new Mock<IFoo>();
_
以下と同じではありません:
_var fooDouble = new Mock<Foo>();
_
私の理解では、IFooのモックを作成するとき、moqフレームワークはIFooインターフェースを実装するdoubleクラスを生成し、生成された実装で自身のデフォルトコンストラクターを提供します。ただし、Fooのモックは、生成されたコードにインターフェイスを直接実装せず、具体的なFooクラスから継承するため、スタブ化するメソッドを仮想化する必要があります。具体的な実装が必要な場合は、実際に使用する(たとえば、テスト対象のユニット)には、モックに「CallBase = true」が必要です。これがコンストラクター引数を持つ具象クラスで実行したい場合、デフォルトのコンストラクターの公開を避けるために@Palkinの答えを探しているかもしれません。
インターフェイスIFoo
があり、パラメーターを持つコンストラクターを持つFoo
クラスをモックする場合は、何も変更しないでください。
あなたのコードはまさにあなたが必要とするものです。
var foo = new Mock<IFoo>();
次のアドバイスは、クラスにインターフェースもパラメーターなしのコンストラクターもない場合の状況をカバーしています。実際、必要なすべてのパラメーターをMock
のコンストラクターに渡すことができます。
var mock = new Mock<IFoo>("constructor", "arguments");
しかし
「最善の方法は、クラスを右クリックして、抽出インターフェイスを選択することです。」 (c)
最善の方法は、クラスを右クリックして[抽出]インターフェースを選択することです。
この概念を直交的な意味で取り上げます。私はこの声明に同意しませんインターフェースは解決策ではありません問題の状況に対して。
前の質問のテキストに戻る:
public class CustomerSyncEngine {
public CustomerSyncEngine(ILoggingProvider loggingProvider,
ICrmProvider crmProvider,
ICacheProvider cacheProvider) { ... }
public void MethodWithDependencies() {
loggingProvider.Log();
crmProvider.Crm();
cacheProvider.Cache();
}
}
追加したメソッドに注意してください。
本当の質問は、CustomerSyncEngine
を具体的にテストするのではなく、代わりにdepends on CustomerSyncEngine
のクラスをテストするときだと思います。このクラスをSuperSyncEngine
と呼びましょう。 SuperSyncEngine
に対するテストの作成は、3つのインターフェイスとCustomerSyncEngine
が持つ他の追加の依存関係とともに、SuperSyncEngine
全体をモックアウトする必要があるため、苦痛になります。
テストしようとしているコードがSuperSyncEngine
であり、これがCustomerSyncEngine
に依存している場合、インターフェイスはここでの答えではありません。あなたはcouldICustomerSyncEngine
を作成できますが、そのインターフェースはモックフレームワークのためだけに作成されるべきではありません。より良い解決策は、CustomerSyncEngine.MethodWithDependencies
は仮想
public virtual void MethodWithDependencies() {
loggingProvider.Log();
crmProvider.Crm();
cacheProvider.Cache();
}
これにより、CustomerSyncEngine
に付属する依存関係を無視して、このメソッドをモックフレームワークに置き換えることができます。
このアプローチに従えば、CustomerSyncEngine
で公開されるデフォルトのコンストラクターが必要になります。あなたはそれを回避し、nullまたは他の値で依存関係を満たすことができますが、目標が摩擦を減らすことである場合は追加の作業になります。
これは一種の古い投稿ですが、同様の問題に遭遇しました(Moqから始めました)。他の誰かが同様の問題を抱えている場合、ここに私が持っていたものがあります:
class Bar : IBar
{
}
class Foo : IFoo
{
public Foo(IBar bar)
{
//initialize etc.
}
//public methods
}
class Manager : IManager
{
public Manager(Foo foo)
{
//initialize etc
}
}
私がやろうとしているのは、Manager
ではなくFoo
をテストすることです。
これがエラーを投げた最初のテストコードです。
[TestFixture]
public class ManagerTest
{
[Test]
public void SomeTest()
{
var fooMock = Mock<IFoo>();
var managerUnderTest = new Manager(fooMock.Object);
}
}
エラーはCastle.DynamicProxy.InvalidProxyConstructorArgumentsException : Can not instantiate proxy of class: Something.Models.Foo. Could not find a parameterless constructor.
エラーメッセージを読むと、パラメーターなしのコンストラクターがないため、MoqはFooをインスタンス化する方法を理解しません。また、パラメーターを使用してコンストラクターをインスタンス化する方法をMoqに伝えません。 2番目のセクションを次のように変更します。
[TestFixture]
public class ManagerTest
{
[Test]
public void SomeTest()
{
var barMock = Mock<IBar>();
var fooMock = Mock<IFoo>(barMock.Object);
var managerUnderTest = new Manager(fooMock.Object);
//proceed with test
}
}
FOoクラスをテストする場合は、モックする必要はありません。テストするクラスに依存するクラスのみをモックする必要があります。
何かのようなもの:
Mock<IBar> bar = new Mock<IBar>();
Mock<IBuzz> buzz = new Mock<IBuzz>();
Mock<IFizz> fizz= new Mock<IFizz>();
Foo foo = new Foo(bar.Object, buzz.Object, fizz.Object);
次に、テストするfooのメソッドを呼び出します;)
Fooのメソッドがbar/fuzzまたはfizz内のメソッドを使用する場合、次のようなsintaxを使用する必要があります。
buzz.Setup(x => x.DoSomething()).Returns(1);
このようにして、fooメソッドが呼び出されると、DoSomethingが呼び出され、常に1が返されます;)
インターフェースは、1つのタイプに複数の実装がある場合に役立ちます。マイナス面では、これは、インターフェイスが必要なためにインターフェイスを派生させないように注意する必要があることを意味します(よくある間違い)。肯定的な面では、モックされたインターフェイスは定義上2番目の実装です。
したがって、結論は次のとおりです。型が他の型の依存関係として機能する場合、インターフェイスを実装するのが適切な候補です。その場合、単体テストでインターフェイスを自由に完全にモックできます。
関連する注意事項として、インターフェイスを定義するときは、インターフェイスに機能部分のみを追加するようにしてください。オブジェクトを定義するメソッドdoesではなく、オブジェクトlikesを定義します。多数のゲッター/セッターとのインターフェースを持つことは、デザインに価値を追加しません。これは理論の非常に大きな領域であり、この小さなウィンドウは、それについてさらに記述する場所ではありません。
あなたの質問との関係を明確にするために:モック化された実装は、インターフェースに必要な動作を提供する必要があります。そのためには、モックフレームワークの機能を使用します。これはFooクラスの具体的な実装とは関係ありません-Mockオブジェクトの特定の動作を定義します。