moq
Validar orden de llamada
Buscar..
Validar orden de llamada implícitamente
Cuando un método que se va a probar usa información de una llamada para pasar a llamadas subsiguientes, un enfoque que puede usarse para asegurar que los métodos se llamen en el orden esperado es configurar las expectativas para reflejar este flujo de datos.
Dado el método para probar:
public void MethodToTest()
{
var str = _utility.GetInitialValue();
str = _utility.PrefixString(str);
str = _utility.ReverseString(str);
_target.DoStuff(str);
}
Las expectativas se pueden configurar para pasar datos de GetInitialValue
través de PrefixString
y ReverseString
a DoStuff
, donde se verifica la información. Si alguno de los métodos se considera fuera de servicio, los datos finales serán incorrectos y la prueba fallará.
// 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));
Validar orden de llamada con devoluciones de llamada
Cuando no puedes / no quieres usar Strict Mocks, no puedes usar MockSequence
para validar el orden de las llamadas. Un enfoque alternativo es utilizar devoluciones de llamada para validar que las expectativas de Setup
se invocan en el orden esperado. Dado el siguiente método para probar:
public void MethodToTest()
{
_utility.Operation1("1111");
_utility.Operation3("3333");
_utility.Operation2("2222");
}
Se puede probar de la siguiente manera:
// 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"));
Validar orden de llamada con MockSequence
Moq proporciona soporte para validar el orden de las llamadas usando MockSequence
, sin embargo, solo funciona cuando se usan MockSequence
estrictos. Por lo tanto, dado el siguiente método para probar:
public void MethodToTest()
{
_utility.Operation1("1111");
_utility.Operation2("2222");
_utility.Operation3("3333");
}
Se puede probar de la siguiente manera:
// 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"));
El ejemplo anterior utiliza It.IsAny<string>
al configurar las expectativas. Estos podrían haber usado cadenas relevantes ("1111", "2222", "3333") si se requieren coincidencias más exactas.
El error informado cuando las llamadas se realizan fuera de secuencia puede ser un poco confuso.
La invocación falló con un comportamiento falso estricto. Todas las invocaciones en el simulacro deben tener una configuración correspondiente.
Esto se debe a que cada expectativa de Setup
se trata como si no existiera hasta que se cumpliera la expectativa anterior en la secuencia.