test mocks mock driven development book and testing tdd mocking rhino-mocks bdd

testing - mocks - test driven development book



Rhino Mocks-Stub.Expect vs.AssertWasCalled (3)

¿Has probado usar

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

De acuerdo, sé que ha habido mucha confusión sobre la nueva sintaxis de AAA en Rhino Mocks, pero tengo que ser honesto, por lo que he visto hasta ahora, me gusta. Lee mejor y ahorra algunas teclas.

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 DAL, y por supuesto, esta está siendo atacada por ahora.

Tenía el siguiente código:

(el manager es el sistema bajo prueba, los data son la interfaz de datos resguardados)

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

El objetivo principal de esta prueba es simplemente asegurarse de que el gerente realmente esté consultando el DAL. Tenga en cuenta que el DAL no está realmente allí, por lo que no hay un valor "real" que regrese.

Sin embargo, esto está fallando ya que necesito 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 no 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 esperadas ¿no?

Si cambio la prueba a (el "1" es la ID esperada a la que está vinculado el recuento):

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

Todo pasa bien, y si cambio la prueba 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 una discusión interesante here , personalmente me gustó esta respuesta .


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

Si no lo está utilizando, su DAL puede devolver cualquier cosa que no importe.

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

Si el conteo de su lista está haciendo algo con el valor que debería, entonces ponga afirmaciones sobre lo que está haciendo. Por ejemplo

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


¿Qué intenta hacer tu prueba?

¿Qué comportamiento o estado estás verificando? Específicamente, ¿está verificando que el colaborador (datos) tiene su método ListCount llamado (prueba basada 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, use un simulacro y una expectativa: use MockRepository.CreateMock<IMyInterface>() y myMock.Expect(x => x.ListCount())

Si quiere resguardar un método, use MockRepository.CreateStub<IMyInterface>() y myStub.Stub(x => x.ListCount()) .

(aparte: sé que puedes usar stub.AssertWasCalled () para lograr casi lo mismo que simulacro. Esperar y con una mejor sintaxis de lectura, pero estoy explorando la diferencia entre mocks y stubs).

Roy Osherove tiene una explicación muy agradable de burlas y trozos.

Por favor publica 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. ¿ ListCount tiene un parámetro de entrada? Si es así, ¿qué representa? ¿Te importa si fue llamado con un cierto valor? ¿Te importa si ListCount devuelve un cierto valor?

Como señaló Simon Laroche, si el Gerente no está haciendo nada con el valor de retorno de ListCount simulado / tropezado, entonces 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, considere tres datos y pronto se dará cuenta de esto:

  1. Qué está siendo probado
  2. En que situación?
  3. ¿Cuál es el resultado esperado?

Compare: pruebas basadas en interacciones con burlas . La llamada en el simulacro es la prueba.

[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(); }

Pruebas basadas en el estado con un stub . 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, estoy a favor de las pruebas basadas en el estado donde sea posible, aunque las pruebas basadas en interacción a menudo se requieren para las API diseñadas con Tell, Do not Ask en mente, ya que no tendrás ningún estado expuesto para verificar.

Confusión de API. 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 te permite establecer expectativas en los resguardos que, para mí, 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.