2008-11-13 40 views
28

Quiero afirmar que un método se llama exactamente una vez. Estoy usando RhinoMocks 3.5.Afirmando que un método se llama exactamente una vez

Aquí es lo que pensé que funcionaría:

[Test] 
public void just_once() 
{ 
    var key = "id_of_something"; 

    var source = MockRepository.GenerateStub<ISomeDataSource>(); 
    source.Expect(x => x.GetSomethingThatTakesALotOfResources(key)) 
     .Return(new Something()) 
     .Repeat.Once(); 

    var client = new Client(soure); 

    // the first call I expect the client to use the source 
    client.GetMeMyThing(key); 

    // the second call the result should be cached 
    // and source is not used 
    client.GetMeMyThing(key); 
} 

Quiero que esta prueba falle si la segunda invocación de GetMeMyThing() llamadas source.GetSomethingThatTakesALotOfResources().

Respuesta

32

Así es como verifico que un método se llama una vez.

[Test] 
public void just_once() 
{ 
    // Arrange 
    var a = MockRepository.GenerateMock<ISomeDataSource>(); 
    a.Expect(x => x.GetSomethingThatTakesALotOfResources()).Return(new Something()).Repeat.Once(); 
    a.Stub(x => x.GetSomethingThatTakesALotOfResources()).Throw(new InvalidOperationException("gotcha")); 

    // Act 
    // First invocation should call GetSomethingThatTakesALotOfResources 
    a.GetMeMyThing(); 

    // Second invocation should return cached result 
    a.GetMeMyThing(); 

    // Assert 
    a.VerifyAllExpectations(); 
} 
+1

+1 para usar 'using (mocks.Record()) {..} Aumenta mucho la legibilidad. –

+0

-1 Esto no funciona. No lanzará una excepción si se llama a GetSomethingThatTakesALotOfResources más de una vez. – Ergwun

+0

Estoy bastante seguro de que esto estaba funcionando en el momento en que escribí esto hace 2 años. Actualizaré la publicación para incluir la nueva forma de hacerlo. –

2

Esto es lo que acabo de hacer (recomendado por Ray Houston). Me gustaría volver a apreciar una solución más elegante ...

[Test] 
public void just_once() 
{ 
    var key = "id_of_something"; 

    var source = MockRepository.GenerateStub<ISomeDataSource>(); 

    // set a positive expectation 
    source.Expect(x => x.GetSomethingThatTakesALotOfResources(key)) 
     .Return(new Something()) 
     .Repeat.Once(); 

    var client = new Client(soure); 

    client.GetMeMyThing(key); 

    // set a negative expectation 
    source.Expect(x => x.GetSomethingThatTakesALotOfResources(key)) 
     .Return(new Something()) 
     .Repeat.Never(); 

    client.GetMeMyThing(key); 
} 
+0

Esto solo funcionaría si su código de llamada fuera lo suficientemente alto como para tener acceso al método repetido. En mi caso, estoy llamando a un método en el que se realizan 2 llamadas dentro de ese método, por lo que no puedo repetir la llamada dentro del cuerpo de prueba. Todavía lo intenté de todos modos, pero el Never() simplemente anula el Once y acabo de esperar. Tengo 0 – PandaWood

4

Usted puede estar interesado en this bit de la burla de Rhino 3.5 Documentación (citado más abajo). Parece que necesitas burlarte de la clase, no andar, para que funcione de la manera que esperas.

La diferencia entre los talones y se burla de

...

Una maqueta es un objeto que podemos establecer expectativas sobre, y que verificará que las acciones que se esperan de hecho tienen ocurrió. Un stub es un objeto que usa para pasar al código bajo la prueba . Puede configurar las expectativas en , por lo que actuaría de cierta manera, pero esas expectativas nunca serán verificadas. Las propiedades de un código auxiliar se se comportarán automáticamente como las propiedades normales , y usted no puede establecer las expectativas en ellas.

Si desea verificar el comportamiento de el código bajo prueba, que va a utilizar una maqueta con la expectativa apropiada, y verificar que. Si solo desea pasar un valor que puede necesitar actuar de una manera determinada en , pero no es el objetivo de esta prueba, usará un código auxiliar.

IMPORTANTE: Un stub nunca hará que falle una prueba .

-1

Tener una función llamada "Exactamente" sería muy útil para escribir pruebas en código que de otro modo podría entrar en un bucle infinito. Me encantaría escribir una prueba para que la segunda llamada a un método genere una excepción.

Algunas bibliotecas para python le permiten secuenciar las expectativas, por lo que la primera devuelve falso y la segunda genera una excepción.

Rhino no hará eso. Un simulacro parcial con .Once interceptará la primera llamada, y el resto pasará al método original. Entonces eso apesta, pero es verdad.

Tendrás que crear un simulacro de mano. Derive una clase "comprobable" y déle la posibilidad de subir después de la primera llamada.

15

He estado utilizando la extensión AssertWasCalled para solucionar este problema. Esto es lo mejor que pude encontrar/pensar, pero sería mejor si no tuviera que especificar la llamada dos veces.

[Test] 
    public void just_once() 
    { 
     var key = "id_of_something"; 

     var source = MockRepository.GenerateStub<ISomeDataSource>(); 

     // set a positive expectation 
     source.Expect(x => x.GetSomethingThatTakesALotOfResources(key)) 
      .Return(new Something()) 
      .Repeat.Once(); 

     var client = new Client(soure); 
     client.GetMeMyThing(key); 
     client.GetMeMyThing(key); 

     source.AssertWasCalled(x => x.GetSomethingThatTakesALotOfResources(key), 
           x => x.Repeat.Once()); 
     source.VerifyAllExpectations(); 
    } 
+0

Gracias, la única respuesta que funcionó para mí. Una diferencia para mí fue que para evitar excepciones internas (nullref) y asegurarme de que obtuve una buena excepción de Rhino Expectation, tuve que repetir Repeat.Twice() para superar el caso de "error". Es por eso que esta solución es buena, esto no importa, AssertWasCalled define exactamente lo que se requiere – PandaWood

+1

¿Qué hace el 'Excpect'? No creo que 'VerifyAllExpectations' funcione en un Stub, solo funciona en un Mock. Pero incluso si funcionaría, ¿de qué sirve? Su 'AssertWasCalled' contiene todas las afirmaciones que necesita. Cambiaría 'Expect' por' Stub' y eliminaría 'Repeat.Once', y también eliminaría' VerifyAllExpectations'. – comecme

2

Puede pasar un delegado a WhenCalled para contar las llamadas:

... 
uint callCount = 0; 
source.Expect(x => x.GetSomethingThatTakesALotOfResources(key)) 
    .Return(new Something()) 
    .WhenCalled((y) => { callCount++; }); 
... 
Assert.AreEqual(1, callCount); 

Además, se debe utilizar una maqueta no un talón, y verificar las expectativas sobre la maqueta también.

0

Puede crear un simulacro estricto, si desea asegurarse de que un método se llame solo una vez.

var mock = MockRepository.GenerateStrictMock<IMustOnlyBeCalledOnce>(); 
mock.Expect(a => a.Process()).Repeat.Once(); 
var helloWorld= new HelloWorld(mock); 

helloworld.Process() 

mock.VerifyAllExpectations(); 
Cuestiones relacionadas