2011-12-28 11 views
10

¿Es posible probar el siguiente ejemplo si el Método1 llamó a 1st, luego Method2 lo llamó y luego Method3 utilizando la sintaxis de AAA, en Rhino-mocks 3.6?¿Puedo probar el orden de las llamadas al método con la sintaxis AAA en Rhino-Mocks 3.6?

// Assert 
var mock = MockRepository.GenerateMock<ISomeService>(); 

// Act 
myObject.Service = mock; 

// How should I change this part to ensure that Rhino Mocks check the call order as well? 
mock.AssertWasCalled(m=>m.Method1()); 
mock.AssertWasCalled(m=>m.Method2()); 
mock.AssertWasCalled(m=>m.Method3()); 

Respuesta

19

Aquí hay una manera de hacerlo ...

mock.AssertWasCalled(m=>m.Method1(), options => options.WhenCalled(w => mockService.AssertWasNotCalled(x=>x.Method2()))); 
mock.AssertWasCalled(m=>m.Method2(), options => options.WhenCalled(w => mockService.AssertWasNotCalled(x=>x.Method3()))); 
mock.AssertWasCalled(m=>m.Method3()); 
8

Puedes, pero que realmente no debería. Debe enfocarse en probar los comportamientos observables externos, en lugar de la implementación.

El método de solicitud de llamada puede cambiar sin afectar el contrato con el cliente de la API. En ese caso, su prueba fallará, incluso cuando no debería.

En resumen, la implementación de pruebas conduce a pruebas frágiles. Las pruebas frágiles conducen al abandono de las pruebas. No quieres ir allí.

Espero que esto ayude.

+16

Este no es siempre el caso. Existen contratos de objetos statefull donde el orden importa y no siempre se puede evitar esos contratos. – sanosdole

+0

Estoy de acuerdo con el comentario de @sanosdole, pero en mi caso fue muy acertado. Debería probar el resultado ... no la implementación. ¡Gracias! – MoMo

+0

Si el código ya tiene acoplamiento temporal, también debe probarse. – SerG

5

He aquí cómo hacerlo bien.

var mocks = new MockRepository(); 
var fooMock = mocks.DynamicMock<IFoo>(); 
using (mocks.Ordered()) 
{ 
    fooMock.Expect(x => x.Method1()); 
    fooMock.Expect(x => x.Method2()); 
} 
fooMock.Replay(); 

var bar = new Bar(fooMock); 
bar.DoWork(); 

fooMock.VerifyAllExpectations(); 

encontrado la respuesta from this blog.

+0

Tuve que enmendar esto ligeramente para que funcione en RhinoMocks 3.5 - ver mi respuesta a continuación. – Clarkeye

+0

No es sintaxis AAA. – SerG

1

es como se hace mediante la construcción de las afirmaciones en cada invocación de métodos aquí.

// Arrange - Build the necessary assertions into the stubbed method invocations. 
var mock = MockRepository.GenerateMock<ISomeService>(); 
mock.Stub(m => m.Method1()).WhenCalled(inv => mock.AssertWasNotCalled(m => m.Method2())); 
mock.Stub(m => m.Method2()).WhenCalled(inv => mock.AssertWasNotCalled(m => m.Method3())); 

// Act 
myObject.Service = mock; 

// Assert - Ensure each expected method was called. 
mock.AssertWasCalled(m => m.Method1()); 
mock.AssertWasCalled(m => m.Method2()); 
mock.AssertWasCalled(m => m.Method3()); 

Dado que se trata se mezcla patrón normal organizar-acto-aserción mediante la ejecución de las afirmaciones a mediados de actuar, me gusta incluir mensajes de error muy específicos para estos casos para identificar fallos de las pruebas con más facilidad.

mock.Stub(m => m.Method1()).WhenCalled(inv => 
    mock.AssertWasNotCalled(m => m.Method2(), opt => 
     opt.Message("Method2 cannot be called before Method1."))); 

También se puede lograr un resultado similar al salvar el resultado de cada invocación de una variable durante el acto paso, y luego la comprobación de los estados variables durante el paso de aserción. Esto preserva mejor la división del patrón arreglar-actuar-afirmar, pero es más un código de plomería para escribir y mantener.

// Arrange - Build the necessary state variables into the stubbed method invocations. 
bool wasMethod1Called; 
bool wasMethod2Called; 
bool wasMethod2CalledBeforeMethod1; 
bool wasMethod3CalledBeforeMethod2; 

var mock = MockRepository.GenerateMock<ISomeService>(); 
mock.Stub(m => m.Method1()).WhenCalled(inv => 
{ 
    wasMethod1Called = true; 
}); 
mock.Stub(m => m.Method2()).WhenCalled(inv => 
{ 
    wasMethod2Called = true; 
    wasMethod2CalledBeforeMethod1 = !wasMethod1Called; 
}); 
mock.Stub(m => m.Method3()).WhenCalled(inv => 
{ 
    wasMethod3CalledBeforeMethod2 = !wasMethod2Called; 
}); 

// Act 
myObject.Service = mock; 

// Assert - Ensure each expected method was called, and that they were called in the right order. 
mock.AssertWasCalled(m => m.Method1()); 
mock.AssertWasCalled(m => m.Method2()); 
mock.AssertWasCalled(m => m.Method3()); 
Assert.That(wasMethod2CalledBeforeMethod1, Is.False, "Method2 cannot be called before Method1."); 
Assert.That(wasMethod3CalledBeforeMethod2, Is.False, "Method3 cannot be called before Method2."); 
0

La sintaxis mocks.Ordered() especificado por @craastad es la forma correcta de hacerlo, pero no pude conseguir que funcione en RhinoMocks 3.5 - en vez tuve que ajustar a trabajar sin la instancia MockRepository de que la solución de @ craastad utiliza para llamar ordenado() en:

var fooMock = MockRepository.GenerateMock<IFoo>(); 
using (fooMock.GetMockRepository().Ordered()) 
{ 
    fooMock.Expect(x => x.Method1()); 
    fooMock.Expect(x => x.Method2()); 
} 

var bar = new Bar(fooMock); 
bar.DoWork(); 

fooMock.VerifyAllExpectations(); 

Si lo haces de esta manera, también parece ser innecesario llamar fooMock.Replay() tampoco.

+3

Alguien marcó esta respuesta, lo cual es justo, pero si vas a hacer eso, ¡lo menos que podrías es explicar por qué! – Clarkeye

Cuestiones relacionadas