2009-01-25 18 views
33

OK, sé que ha habido mucha confusión sobre la nueva sintaxis AAA en burla de Rhino, pero tengo que ser honesto, por lo que he visto hasta ahora, me gusta. Lee mejor y ahorra algunas teclas.se burla de Rhino - Trozo .Expect vs .AssertWasCalled

Básicamente, estoy probando un ListController que básicamente se encargará de algunas listas de cosas :) He creado una interfaz que eventualmente se convertirá en el DAL, y esto por supuesto se está cortando por ahora.

que tenían el siguiente código:

(manager es el sistema bajo prueba, data es la interfaz de datos stubbed)

[Fact] 
    public void list_count_queries_data() 
    { 
     data.Expect(x => x.ListCount(1)); 
     manager.ListCount(); 
     data.VerifyAllExpectations(); 
    } 

El principal objetivo de esta prueba es asegurar simplemente que el gerente es en realidad consultar el DAL. Tenga en cuenta que el DAL no es realmente incluso allí, así que no hay valor "real" volver ..

Sin embargo, esto está fallando ya que necesito para cambiar la expectativa de tener un valor de retorno, como:

 data.Expect(x => x.ListCount(1)).Return(1); 

Esto funcionará bien, y la prueba pasará, sin embargo - lo que me confunde es que en este momento, el valor de retorno significa nada. Puedo cambiarlo a 100, 50, 42, lo que sea y la prueba siempre pasará?

Esto me pone nervioso, porque una prueba debe ser explícita y debe fallar por completo si no se cumplen las condiciones previstas ¿no?

Si cambio de la prueba a (el "1" es el ID esperado el conteo está vinculada a):

[Fact] 
    public void list_count_queries_data() 
    { 
     manager.ListCount(); 
     data.AssertWasCalled(x => x.ListCount(1)); 
    } 

Todo pasa bien, y si me cambio la prueba en su cabeza a AssertWasNotCalled, falla como se esperaba ... ¡También creo que se lee mucho mejor, es más claro sobre lo que se está probando y lo más importante PASA y NO PASA como se esperaba!

Entonces, ¿me falta algo en el primer ejemplo de código? ¿Qué piensas sobre hacer afirmaciones en los talones? (Hubo alguna discusión interesante here, personalmente me ha gustado this response.

+1

estuvo de acuerdo - gracias por la mano a mano, una pregunta muy vieja que se había perdido en el polvo. –

Respuesta

52

Lo que está tratando su prueba lograr?

¿Qué comportamiento o estado está comprobando? Específicamente, ¿está verificando que el colaborador (datos) tiene su método ListCount llamado (pruebas basadas en la interacción), o simplemente desea hacer que ListCount devuelva un valor enlatado para controlar la clase bajo prueba mientras se verifica el resultado en otro lugar (estado tradicional basado pruebas)?

Si desea establecer una expectativa, utilice una maqueta y una expectativa: Uso MockRepository.CreateMock<IMyInterface>() y myMock.Expect(x => x.ListCount())

Si desea un método de código auxiliar, utilice MockRepository.CreateStub<IMyInterface>() y myStub.Stub(x => x.ListCount()).

(aparte: Sé que usted puede utilizar stub.AssertWasCalled() para lograr lo mismo como mock.Expect y posiblemente mejor con la lectura de sintaxis, pero sólo estoy de agujerear la diferencia entre burla & talones).

Roy Osherove has a very nice explanation of mocks and stubs.

Por favor enviar más código!

Necesitamos una imagen completa de cómo está creando el stub (o simulacro) y cómo se usa el resultado con respecto a la clase bajo prueba. ¿Tiene ListCount un parámetro de entrada? Si es así, ¿qué representa? ¿Le importa si fue llamado con un cierto valor? ¿Le importa si ListCountdevuelve un cierto valor?

Como Simon Laroche señaló, si el Administrador no está haciendo nada con el valor de retorno de ListCount, la prueba no pasará o fallará debido a ello. Todo lo que la prueba esperaría es que se llame al método simulado/burlado, nada más.

Para comprender mejor el problema, consideran tres tipos de información y que pronto resolver esto:

  1. Lo que se está probando
  2. En qué situación?
  3. ¿Cuál es el resultado esperado?

Compare: pruebas basadas Interacción con burla. La llamada en el simulacro es la prueba. pruebas basadas

[Test] 
public void calling_ListCount_calls_ListCount_on_DAL() 
{ 
    // Arrange 
    var dalMock = MockRepository.Mock<IDAL>(); 
    var dalMock.Expect(x => x.ListCount()).Returns(1); 
    var manager = new Manager(dalMock); 

    // Act 
    manager.ListCount(); 

    // Assert -- Test is 100% interaction based 
    dalMock.VerifyAllExpectations(); 
} 

Estado con un talón de. El talón conduce la prueba, pero no es parte de la expectativa.

[Test] 
public void calling_ListCount_returns_same_count_as_DAL() 
{ 
    // Arrange 
    var dalStub = MockRepository.Stub<IDAL>(); 
    var dalStub.Stub(x => x.ListCount()).Returns(1); 
    var manager = new Manager(dalMock); 

    // Act 
    int listCount = manager.ListCount(); 

    // Assert -- Test is 100% state based 
    Assert.That(listCount, Is.EqualTo(1), 
     "count should've been identical to the one returned by the dal!"); 
} 

personalmente a favor de las pruebas basadas en el estado en que es posible, a pesar de las pruebas basadas en la interacción es a menudo necesaria para las API que están diseñados con Tell, Don't Ask en cuenta, ya que no tendrá ningún estado expuesto a verificar en contra!

API Confusion. Mocks no es stubs. ¿O son?

La distinción entre un simulacro y un talón en el rinoceronte se burla. Tradicionalmente, los stubs no están destinados a tener expectativas, por lo tanto, si su prueba doble no tuvo su método llamado, esto no provocaría directamente la falla de la prueba.

... Sin embargo, la API de Rhino Mocks es potente, pero confusa ya que permite establecer expectativas en los resguardos que, en mi opinión, va en contra de la terminología aceptada. Tampoco creo mucho de la terminología, mente. Sería mejor si la distinción se eliminara y los métodos requeridos en la prueba establecieran el rol, en mi opinión.

+0

+1 de mí. También soy nuevo en Rhino Mocks. Gracias por mostrar .Stub. Había estado usando. Espere porque eso fue lo que usaron todos los ejemplos ... – Edward

+0

Siempre hago pruebas de comportamiento usando stubs, como se hace en la publicación de ayende: http://ayende.com/blog/3384/rhino-mocks- 3-5-design-decisions-the-role-of-stub-vs-mock –

+0

+1 para la confusión API. Exactamente lo que pienso ... – 70sCommander

1

Creo que tiene que ver con lo que su manager.ListCount() está haciendo con el valor de retorno.

Si no lo está utilizando, entonces su DAL puede devolver nada, no importará.

public class Manager 
{ 
    public Manager(DAL data) 
    { 
     this.data = data 
    } 
    public void ListCount() 
    { 
     data.ListCount(1); //Not doing anything with return value 
     DoingSomeOtherStuff(); 
    }  
} 

Si la lista de recuento está haciendo algo con el valor que debe a continuación, poner las afirmaciones sobre lo que está haciendo. Por exemple

Assert.IsTrue(manager.SomeState == "someValue"); 
+0

+1 para la distinción entre la expectativa de la prueba doble y la prueba basada en el estado –

0

¿Ha intentado utilizar

data.AssertWasCalled(x => x.ListCount(1) = Arg.Is(EXPECTED_VALUE)); 
Cuestiones relacionadas