2011-02-10 2 views
100
public void SubmitMessagesToQueue_OneMessage_SubmitSuccessfully() 
{ 
    var messageServiceClientMock = new Mock<IMessageServiceClient>(); 
    var queueableMessage = CreateSingleQueueableMessage(); 
    var message = queueableMessage[0]; 
    var xml = QueueableMessageAsXml(queueableMessage); 
    messageServiceClientMock.Setup(proxy => proxy.SubmitMessage(xml)).Verifiable(); 
    //messageServiceClientMock.Setup(proxy => proxy.SubmitMessage(It.IsAny<XmlElement>())).Verifiable(); 

    var serviceProxyFactoryStub = new Mock<IMessageServiceClientFactory>(); 
    serviceProxyFactoryStub.Setup(proxyFactory => proxyFactory.CreateProxy()).Returns(essageServiceClientMock.Object); 
    var loggerStub = new Mock<ILogger>(); 

    var client = new MessageClient(serviceProxyFactoryStub.Object, loggerStub.Object); 
    client.SubmitMessagesToQueue(new List<IMessageRequestDTO> {message}); 

    //messageServiceClientMock.Verify(proxy => proxy.SubmitMessage(xml), Times.Once()); 
    messageServiceClientMock.Verify(); 
} 

私はMoqを使用して少し苦労しています。 messageServiceClientがXmlElementである正しいパラメータを受け取っていることを確認しようとしていますが、動作させる方法が見つかりません。特定の値をチェックしない場合にのみ機能します。Moqで特定のパラメータを確認しています

アイデア?

部分的な答え: プロキシに送信されたxmlが正しいことをテストする方法を見つけましたが、それでも正しい方法はないと思います。

public void SubmitMessagesToQueue_OneMessage_SubmitSuccessfully() 
{ 
    var messageServiceClientMock = new Mock<IMessageServiceClient>(); 
    messageServiceClientMock.Setup(proxy => proxy.SubmitMessage(It.IsAny<XmlElement>())).Verifiable(); 
    var serviceProxyFactoryStub = new Mock<IMessageServiceClientFactory>(); 
    serviceProxyFactoryStub.Setup(proxyFactory => proxyFactory.CreateProxy()).Returns(messageServiceClientMock.Object); 
    var loggerStub = new Mock<ILogger>(); 

    var client = new MessageClient(serviceProxyFactoryStub.Object, loggerStub.Object); 
    var message = CreateMessage(); 
    client.SubmitMessagesToQueue(new List<IMessageRequestDTO> {message}); 

    messageServiceClientMock.Verify(proxy => proxy.SubmitMessage(It.Is<XmlElement>(xmlElement => XMLDeserializer<QueueableMessage>.Deserialize(xmlElement).Messages.Contains(message))), Times.Once()); 
} 

ところで、私はVerify呼び出しからどのように式を抽出できますか?

答えて

149

検証ロジックが些細でない場合は、大きなラムダメソッドを記述するのが面倒です(例のように)。すべてのテストステートメントを別々のメソッドに入れることはできますが、テストコードの読み込みの流れが乱れるので、これをしたくありません。

もう1つの方法は、セットアップコールでコールバックを使用して模擬メソッドに渡された値を格納し、それを検証する標準のAssertメソッドを記述することです。たとえば:

// Arrange 
MyObject saveObject; 
mock.Setup(c => c.Method(It.IsAny<int>(), It.IsAny<MyObject>())) 
     .Callback<int, MyObject>((i, obj) => saveObject = obj) 
     .Returns("xyzzy"); 

// Act 
// ... 

// Assert 
// Verify Method was called once only 
mock.Verify(c => c.Method(It.IsAny<int>(), It.IsAny<MyObject>()), Times.Once()); 
// Assert about saveObject 
Assert.That(saveObject.TheProperty, Is.EqualTo(2)); 
+5

このアプローチの大きな利点の1つは、オブジェクトをどのように不正確にするか(それぞれを個別にテストする場合) –

+1

私はこれをやった唯一の人だと思って、妥当なアプローチであることを嬉しく思っています! –

+0

私はそれを使用すると思います。(バリデータ)Mayoの方がラムダの一部としてパラメータ値を保存するというやや厄介な方法 – stevec

48

私は同じ方法で通話を確認しています。私はそれが正しい方法だと信じています。

mockSomething.Verify(ms => ms.Method(
    It.IsAny<int>(), 
    It.Is<MyObject>(mo => mo.Id == 5 && mo.description = "test") 
), Times.Once()); 

あなたのラムダ式が扱いにくくなった場合、あなたは真/偽入力および出力としてMyObjectに取る関数を作成することができます...

mockSomething.Verify(ms => ms.Method(
    It.IsAny<int>(), 
    It.Is<MyObject>(mo => MyObjectFunc(mo)) 
), Times.Once()); 

private bool MyObjectFunc(MyObject myObject) 
{ 
    return myObject.Id == 5 && myObject.description == "test"; 
} 

また、モックのバグを意識しますエラーメッセージは、メソッドがまったく呼び出されなかったときに複数回呼び出されたことを示します。彼らは今修正しているかもしれませんが、そのメッセージが表示されたら、そのメソッドが実際に呼び出されたことを検証することを検討するかもしれません。

EDIT:ここでは、リスト内のオブジェクトごとに関数を呼び出すことを確認するシナリオで、複数回検証を呼び出す例を示します。セットアップのための

foreach (var item in myList) 
    mockRepository.Verify(mr => mr.Update(
    It.Is<MyObject>(i => i.Id == item.Id && i.LastUpdated == item.LastUpdated), 
    Times.Once()); 

同じアプローチ...

foreach (var item in myList) { 
    var stuff = ... // some result specific to the item 
    this.mockRepository 
    .Setup(mr => mr.GetStuff(item.itemId)) 
    .Returns(stuff); 
} 

だからGetStuffは、その品目IDのために呼び出されるたびに、その項目に固有のものを返します。あるいは、itemIdを入力として取得し、stuffを返す関数を使用することもできます。機能は、それがキューからアイテムを引き上げると呼ばれていたたびに - 私はいくつかの時間バックのブログで見た

this.mockRepository 
    .Setup(mr => mr.GetStuff(It.IsAny<int>())) 
    .Returns((int id) => SomeFunctionThatReturnsStuff(id)); 

もう一つの方法は、(?フィル・ハークは、おそらく)デキューオブジェクトのいくつかの種類から戻ってセットアップを持っていました。

+0

おかげで、それは私には意味があります。 私がまだ理解できないことは、セットアップまたは確認で詳細を指定するときです。それはかなり混乱しています。現時点では、セットアップで何かを許可し、検証で値を指定しています。 –

+0

複数の通話があるときに、どのようにメッセージを確認できると思いますか? クライアントはメッセージを受け取り、複数の呼び出しで終了する複数のqueueableMessagesを作成できます。これらの呼び出しのそれぞれで、別のメッセージをチェックする必要があります。 私は一般的に単体テストに苦労していますが、私はあまりよく分かりません。 –

+0

私はあなたがこれをやるべきであるという点で魔法の銀色の弾丸があるとは思わない。それは練習を必要とし、あなたはより良くなり始めます。私にとって、私はそれらを比較するものがあるときと、別のテストでそのパラメータをまだテストしていないときだけ、パラメータを指定します。複数の呼び出しに関しては、いくつかのアプローチがあります。複数回呼び出される関数を設定して検証するために、私は通常、forループを使用して、想定している呼び出しごとにsetupまたはverify(Times.Once())を呼び出します。特定のパラメータを使用して、各コールを分離することができます。 – Mayo

1

私はMoqが同等性をチェックするという事実の問題を信じています。また、XmlElementはEqualsをオーバーライドしないため、実装は参照の等価性をチェックします。

カスタムオブジェクトを使用できないため、equalsをオーバーライドできますか?

+0

はい、私はそれをやり終えた。私は問題がXmlをチェックしていることに気づいた。 2番目の質問では、xmlをオブジェクトにデシリアライズする可能性のある回答を追加しました –

8

簡単な方法を行うには、次のようになります。

ObjectA.Verify(
    a => a.Execute(
     It.Is<Params>(p => p.Id == 7) 
    ) 
); 
関連する問題