サーチ…
呼び出し順序を暗黙的に検証する
テストされるメソッドが、あるコールからの情報を後続のコールに渡すために使用される場合、メソッドが期待される順序で確実に呼び出されるようにするための1つのアプローチは、このデータフローを反映するための期待を設定することです。
与えられたテスト方法:
public void MethodToTest()
{
var str = _utility.GetInitialValue();
str = _utility.PrefixString(str);
str = _utility.ReverseString(str);
_target.DoStuff(str);
}
期待がデータ渡すように設定することができるGetInitialValue
介しPrefixString
とReverseString
にDoStuff
情報が検証されます。いずれかのメソッドが順不同で呼び出された場合、終了データは間違っており、テストは失敗します。
// Create mocks
var utilityMock = new Mock<IUtility>();
var targetMock = new Mock<ITarget>();
// Setup expectations, note that the returns value from one call matches the expected
// parameter for the next call in the sequence of calls we're interested in.
utilityMock.Setup(x => x.GetInitialValue()).Returns("string");
utilityMock.Setup(x => x.PrefixString("string")).Returns("Prefix:string");
utilityMock.Setup(x => x.ReverseString("Prefix:string")).Returns("gnirts:xiferP");
string expectedFinalInput = "gnirts:xiferP";
// Invoke the method to test
var sut = new SystemUnderTest(utilityMock.Object, targetMock.Object);
sut.MethodToTest();
// Validate that the final call was passed the expected value.
targetMock.Verify(x => x.DoStuff(expectedFinalInput));
コールバックによるコール順序の検証
Strict MockSequence
を使用できない/したくない場合は、 MockSequence
を使用して呼び出し順序を検証することはできません。別の方法として、コールバックを使用して、 Setup
期待値が予想された順序で呼び出されていることを検証する方法がありSetup
。次のテスト方法を考えます。
public void MethodToTest()
{
_utility.Operation1("1111");
_utility.Operation3("3333");
_utility.Operation2("2222");
}
次のようにテストできます。
// Create the mock (doesn't have to be in strict mode)
var utilityMock = new Mock<IUtility>();
// Create a variable to track the current call number
int callOrder = 1;
// Setup each call in the sequence to be tested. Note that the callback validates that
// that callOrder has the expected value, then increments it in preparation for the next
// call.
utilityMock.Setup(x => x.Operation1(It.IsAny<string>()))
.Callback(() => Assert.AreEqual(1, callOrder++, "Method called out of order") );
utilityMock.Setup(x => x.Operation2(It.IsAny<string>()))
.Callback(() => Assert.AreEqual(2, callOrder++, "Method called out of order") );
utilityMock.Setup(x => x.Operation3(It.IsAny<string>()))
.Callback(() => Assert.AreEqual(3, callOrder++, "Method called out of order") );
// Invoke the method to be tested
var sut = new SystemUnderTest(utilityMock.Object);
sut.MethodToTest();
// Validate any parameters that are important, note these Verifications can occur in any
// order.
utilityMock.Verify(x => x.Operation2("2222"));
utilityMock.Verify(x => x.Operation1("1111"));
utilityMock.Verify(x => x.Operation3("3333"));
MockSequenceを使用した呼び出し順序の検証
MoqはMockSequenceを使用して呼び出し順序の検証をサポートしていMockSequence
、Strict MockSequence
を使用している場合にのみ機能します。だから、次のテスト方法を考えてみましょう:
public void MethodToTest()
{
_utility.Operation1("1111");
_utility.Operation2("2222");
_utility.Operation3("3333");
}
次のようにテストできます。
// Create the mock, not MockBehavior.Strict tells the mock how to behave
var utilityMock = new Mock<IUtility>(MockBehavior.Strict);
// Create the MockSequence to validate the call order
var sequence = new MockSequence();
// Create the expectations, notice that the Setup is called via InSequence
utilityMock.InSequence(sequence).Setup(x => x.Operation1(It.IsAny<string>()));
utilityMock.InSequence(sequence).Setup(x => x.Operation2(It.IsAny<string>()));
utilityMock.InSequence(sequence).Setup(x => x.Operation3(It.IsAny<string>()));
// Run the method to be tested
var sut = new SystemUnderTest(utilityMock.Object);
sut.MethodToTest();
// Verify any parameters that are cared about to the operation being orchestrated.
// Note that the Verify calls can be in any order
utilityMock.Verify(x => x.Operation2("2222"));
utilityMock.Verify(x => x.Operation1("1111"));
utilityMock.Verify(x => x.Operation3("3333"));
上記の例では、期待値を設定するときにIt.IsAny<string>
使用しています。より正確な一致が必要な場合は、関連する文字列( "1111"、 "2222"、 "3333")を使用している可能性があります。
呼び出しが順不同で行われたときに報告されるエラーは、少し誤解を招く可能性があります。
モックの動作で呼び出しが失敗しました。モック上のすべての呼び出しには、対応する設定が必要です。
これは、各Setup
期待値が、シーケンスの前の期待値が満たされるまで存在しないかのように扱われるためです。