2016-09-27 4 views
1

Moq 4.5フレームワークのSetupSequenceメソッドを使用しようとしています。Moq SetupSequenceが機能しない

嘲笑されなければならないクラス:

public class OutputManager { 
    public virtual string WriteMessage(string message) { 
    // write a message 
    } 
} 

モック:

var outputManagerMock = new Mock<OutputManager>(); 
var writeMessageCalls = 0; 
var currentMessage = String.Empty; 

outputManagerMock.Setup(o => o.WriteMessage(It.IsAny<string>())).Callback((string m) => { 
    writeMessageCalls++; 
    message = m; 
}); 

このコードは正常に動作します。しかし、WriteMessageメソッドの呼び出しごとに異なる設定をしたいと思います。まあ、私はSetupSequence代わりのSetup使用:

var outputManagerMock = new Mock<OutputManager>(); 
var writeMessageCalls = 0; 
var firstMessage = String.Empty; 
var secondMessage = String.Empty; 

outputManagerMock.SetupSequence(o => o.WriteMessage(It.IsAny<string>())) 
.Callback((string m) => { 
    writeMessageCalls++; 
    firstMessage = m; 
}).Callback((string m) => { 
    writeMessageCalls++; 
    secondMessage = m; 
}); 

は、その後、私はエラーを持っている:私はここに可能な解決策を見つけた

Error CS0411 The type arguments for method
'SequenceExtensions.SetupSequence<TMock, TResult>(Mock<TMock>, Expression<Func<TMock, TResult>>)' cannot be inferred from the usage.
Try specifying the type arguments explicitly.

からSetupSequence in Moq。しかし、それは回避策のように見えます。

+0

は、あなたが実際に 'SetupSequence' – Nkosi

+0

はまた' OutputManager.WriteMessage'が仮想であるべきか、部品番号は、例外がスローされます使用してコードを表示します。 – Nkosi

+0

はい、それはもちろん仮想です。コードサンプルを更新しました。 – Sergey

答えて

1

OutputManagerなら、あなたはそれが簡単にあなたのテストのために模擬するために作るために、そのクラスを抽象化を検討すべきです。

public interface IOutputManager { 
    string WriteMessage(string message); 
} 

これは、このインターフェイスの実装が、最初にインターフェイスを追加したものと同じに見えることを意味します。

public class OutputManager : IOutputManager { 
    public string WriteMessage(string message) { 
     // write a message 
    } 
} 

は、最初にOutputManagerを模擬しようとしたことを考えると、その後、ここでの仮定を使用すると、一般的に、テストの対象ではなく、その依存関係を嘲笑していないとして、それはテスト対象のシステムではないということです。

従属クラスをこのように見てみましょう。

public class DependentOnIOutputManager { 
    private IOutputManager outputManager; 

    public DependentOnIOutputManager(IOutputManager outputManager) { 
     this.outputManager = outputManager; 
    } 

    public string SomeMethod(string message) {   
     // write a message 
     var output = outputManager.WriteMessage(message); 
     //...other code 
     return output; 
    } 
} 

次に、テストの例は次のようになります。

[TestMethod] 
public void Moq_SetupSequence_Example() { 
    //Arrange 
    var mock = new Mock<IOutputManager>(); 

    mock.SetupSequence(x => x.WriteMessage(It.IsAny<string>())) 
     .Returns("first") 
     .Returns("second") 
     .Throws<InvalidOperationException>(); 

    var outputManager = mock.Object; 

    var sut = new DependentOnIOutputManager(outputManager); 

    //Act 
    var first = sut.SomeMethod("1st"); 

    var second = sut.SomeMethod("2nd"); 

    Exception e = null; 
    try { 
     sut.SomeMethod("3rd"); 
    } catch (InvalidOperationException ex) { 
     e = ex; 
    } 

    //Assert 
    Assert.IsNotNull(first); 
    Assert.IsNotNull(second); 
    Assert.IsNotNull(e); 
} 
+0

おかげさまで、あなたのアイデアはIOutputManagerインターフェイスでうまく聞こえます。 – Sergey

+0

喜んで助けてください。この回答によって問題が解決された場合は、回答としてマークすることができます。この回答が役に立つ場合は、投票アップすることもできます。 – Nkosi

+0

それは役に立ちます。 – Sergey

2

SetupSequenceは、設定中のメソッドを使用しようと試みた回数に基づいて一連の戻り値を設定するために使用されます。あなたのコードに基づいた例は、私が何を言っているかを示しています。他のクラスの依存関係がある

outputManagerMock.SetupSequence(o => o.WriteMessage(It.IsAny<string>())) 
.Returns("Hello for the first attempt!") 
.Returns("This is the second attempt to access me!") 
.Throws(new Exception()); 
+0

'outputManagerMock.SetupSequence(...)'を意味しますか? '.Setup(...)'だけでなく? – Sergey

+0

確かにそうです。申し訳ありません! –

関連する問題