moq
Convalida dell'ordine di chiamata
Ricerca…
Convalida implicita dell'ordine di chiamata
Quando un metodo da testare utilizza le informazioni di una chiamata per passare alle chiamate successive, un approccio che può essere utilizzato per garantire che i metodi siano richiamati nell'ordine previsto è quello di impostare le aspettative per riflettere questo flusso di dati.
Dato il metodo per testare:
public void MethodToTest()
{
var str = _utility.GetInitialValue();
str = _utility.PrefixString(str);
str = _utility.ReverseString(str);
_target.DoStuff(str);
}
Le aspettative possono essere impostate per passare i dati da GetInitialValue
a PrefixString
e ReverseString
a DoStuff
, dove vengono verificate le informazioni. Se uno qualsiasi dei metodi viene chiamato fuori servizio, i dati finali saranno errati e il test avrà esito negativo.
// 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));
Convalida dell'ordine di chiamata con callback
Quando non puoi / non vuoi usare Strict Mocks, non puoi usare MockSequence
per convalidare l'ordine di chiamata. Un approccio alternativo consiste nell'utilizzare i callback per verificare che le aspettative di Setup
vengano invocate nell'ordine previsto. Dato il seguente metodo per testare:
public void MethodToTest()
{
_utility.Operation1("1111");
_utility.Operation3("3333");
_utility.Operation2("2222");
}
Può essere testato come segue:
// 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"));
Convalida dell'ordine di chiamata con MockSequence
Moq fornisce il supporto per convalidare l'ordine di chiamata usando MockSequence
, tuttavia funziona solo quando si usano i mock rigorosi. Quindi, visto il seguente metodo per testare:
public void MethodToTest()
{
_utility.Operation1("1111");
_utility.Operation2("2222");
_utility.Operation3("3333");
}
Può essere testato come segue:
// 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"));
L'esempio precedente utilizza It.IsAny<string>
quando si impostano le aspettative. Questi potrebbero aver usato stringhe rilevanti ("1111", "2222", "3333") se fossero richieste corrispondenze più esatte.
L'errore segnalato quando le chiamate sono fatte fuori sequenza può essere un po 'fuorviante.
invocazione fallita con comportamento simulato rigoroso. Tutte le invocazioni sulla simulazione devono avere una configurazione corrispondente.
Questo perché, ogni Setup
aspettativa è trattata come se non esiste finché l'aspettativa precedente nella sequenza è rispettato.