unit test que ejemplo diferencia atdd unit-testing mocking terminology definition stub

unit-testing - test - tdd ejemplo



¿Cuál es la diferencia entre fingir, burlarse y apestar? (7)

Lo que usted afirma en él, se llama un objeto simulado y todo lo demás que ayudó a la ejecución de la prueba, es un código auxiliar .

Sé cómo uso estos términos, pero me pregunto si hay definiciones aceptadas para simular , burlarse y aplastar para pruebas de unidad. ¿Cómo se definen estos para sus pruebas? Describe las situaciones en las que podrías usar cada una.

Así es como los uso:

Fake : una clase que implementa una interfaz pero que contiene datos fijos y no lógica. Simplemente devuelve datos "buenos" o "malos" según la implementación.

Simulacro : una clase que implementa una interfaz y permite la capacidad de establecer dinámicamente los valores para devolver / excepciones para lanzar desde métodos particulares y proporciona la capacidad de verificar si se han llamado / no llamado métodos particulares.

Stub : como una clase simulada, excepto que no proporciona la capacidad de verificar que los métodos hayan sido llamados / no llamados.

Las simulaciones y los apéndices pueden generarse a mano o generarse mediante un marco de simulación. Las clases falsas se generan a mano. Uso simulacros principalmente para verificar las interacciones entre mi clase y las clases dependientes. Utilizo stubs una vez que he verificado las interacciones y estoy probando rutas alternativas a través de mi código. Utilizo clases falsas principalmente para abstraer las dependencias de datos o cuando las simulaciones / talones son demasiado tediosos para configurar cada vez.


Me sorprende que esta pregunta haya existido durante tanto tiempo y que nadie haya proporcionado una respuesta basada en "El arte de las pruebas unitarias" de Roy Osherove .

En "3.1 Introducción de stubs" define un stub como:

Un apéndice es un reemplazo controlable de una dependencia existente (o colaborador) en el sistema. Al usar un código auxiliar, puede probar su código sin tratar directamente con la dependencia.

Y define la diferencia entre stubs y mocks como:

Lo más importante que debe recordar acerca de los simulacros frente a los apéndices es que los simulacros son como talones, pero usted afirma contra el objeto simulado, mientras que no lo hace contra un talón.

Fake es solo el nombre que se usa tanto para los stubs como para los mocks. Por ejemplo, cuando no te importa la distinción entre stubs y mocks.

La forma en que Osherove distingue entre stubs y simulacros, significa que cualquier clase utilizada como falso para pruebas puede ser tanto un stub como un simulacro. Lo que corresponde a una prueba específica depende completamente de cómo escriba los controles en su prueba.

  • Cuando su prueba verifica los valores en la clase bajo prueba, o en realidad en cualquier lugar que no sea falso, la falsificación se usó como un código auxiliar. Simplemente proporcionó valores para la clase bajo prueba para usar, ya sea directamente a través de los valores devueltos por las llamadas en él o indirectamente a través de causar efectos secundarios (en algún estado) como resultado de las llamadas en él.
  • Cuando su prueba verifica los valores de la falsificación, se usó como un simulacro.

Ejemplo de una prueba en la que se utiliza la clase FakeX como código auxiliar:

const pleaseReturn5 = 5; var fake = new FakeX(pleaseReturn5); var cut = new ClassUnderTest(fake); cut.SquareIt; Assert.AreEqual(25, cut.SomeProperty);

La instancia fake se usa como un código auxiliar porque Assert no usa fake en absoluto.

Ejemplo de una prueba donde se usa la clase de prueba X como simulacro:

const pleaseReturn5 = 5; var fake = new FakeX(pleaseReturn5); var cut = new ClassUnderTest(fake); cut.SquareIt; Assert.AreEqual(25, fake.SomeProperty);

En este caso, Assert verifica un valor en fake , haciendo que sea falso un simulacro.

Ahora, por supuesto, estos ejemplos son altamente artificiales, pero veo un gran mérito en esta distinción. Te hace consciente de cómo estás probando tus cosas y dónde están las dependencias de tu prueba.

Estoy de acuerdo con Osherove en que

Desde una perspectiva de mantenibilidad pura, en mis pruebas el uso de simulacros crea más problemas que no usarlos. Esa ha sido mi experiencia, pero siempre estoy aprendiendo algo nuevo.

Afirmar en contra de lo falso es algo que realmente desea evitar, ya que hace que sus pruebas sean altamente dependientes de la implementación de una clase que no es la que está bajo prueba en absoluto. Lo que significa que las pruebas para la clase ActualClassUnderTest pueden comenzar a romperse porque la implementación de ClassUsedAsMock cambió. Y eso me envía un mal olor. Las pruebas para ActualClassUnderTest preferiblemente deberían romperse cuando se cambia ActualClassUnderTest .

Me doy cuenta de que escribir afirmaciones contra lo falso es una práctica común, especialmente cuando eres un tipo de suscriptor de TDD. Supongo que estoy firmemente con Martin Fowler en el campo clasicista (ver "Los simulacros no son talones de Martin Fowler" ) y al igual que Osherove, evita las pruebas de interacción (lo que solo se puede hacer afirmando contra lo falso) tanto como sea posible.

Para leer por qué debería evitar los simulacros como se define aquí, busque en google "clasicista mockist fowler". Encontrarás una plétora de opiniones.


Para ilustrar el uso de talones y simulacros, también me gustaría incluir un ejemplo basado en " El arte de las pruebas unitarias " de Roy Osherove.

Imagínese, tenemos una aplicación LogAnalyzer que tiene la única funcionalidad de imprimir registros. No solo necesita hablar con un servicio web, sino que si el servicio web genera un error, LogAnalyzer debe registrar el error en una dependencia externa diferente, enviándolo por correo electrónico al administrador del servicio web.

Aquí está la lógica que nos gustaría probar dentro de LogAnalyzer:

if(fileName.Length<8) { try { service.LogError("Filename too short:" + fileName); } catch (Exception e) { email.SendEmail("a","subject",e.Message); } }

¿Cómo comprueba que LogAnalyzer llama el servicio de correo electrónico correctamente cuando el servicio web lanza una excepción? Aquí están las preguntas que enfrentamos:

  • ¿Cómo podemos reemplazar el servicio web?

  • ¿Cómo podemos simular una excepción del servicio web para poder probar la llamada al servicio de correo electrónico?

  • ¿Cómo sabremos que el servicio de correo electrónico fue llamado correctamente o en absoluto?

Podemos tratar las dos primeras preguntas usando un talón para el servicio web . Para resolver el tercer problema, podemos usar un objeto simulado para el servicio de correo electrónico .

Una falsificación es un término genérico que puede usarse para describir un código auxiliar o un simulacro. En nuestra prueba, tendremos dos falsificaciones. Uno será el simulacro del servicio de correo electrónico, que utilizaremos para verificar que los parámetros correctos se enviaron al servicio de correo electrónico. El otro será un código auxiliar que usaremos para simular una excepción lanzada desde el servicio web. Es un trozo porque no usaremos el servicio web falso para verificar el resultado de la prueba, solo para asegurarnos de que la prueba se ejecute correctamente. El servicio de correo electrónico es un simulacro porque afirmaremos contra él que fue llamado correctamente.

[TestFixture] public class LogAnalyzer2Tests { [Test] public void Analyze_WebServiceThrows_SendsEmail() { StubService stubService = new StubService(); stubService.ToThrow= new Exception("fake exception"); MockEmailService mockEmail = new MockEmailService(); LogAnalyzer2 log = new LogAnalyzer2(); log.Service = stubService log.Email=mockEmail; string tooShortFileName="abc.ext"; log.Analyze(tooShortFileName); Assert.AreEqual("a",mockEmail.To); //MOCKING USED Assert.AreEqual("fake exception",mockEmail.Body); //MOCKING USED Assert.AreEqual("subject",mockEmail.Subject); } }


Puedes obtener alguna información:

De Martin Fowler sobre Mock y Stub

Los objetos falsos realmente tienen implementaciones de trabajo, pero usualmente toman algún atajo que los hace inadecuados para la producción

Los apéndices brindan respuestas enlatadas a las llamadas realizadas durante la prueba, por lo general, no responden en absoluto a nada fuera de lo que está programado para la prueba. Los stubs también pueden registrar información sobre las llamadas, como un stub de pasarela de correo electrónico que recuerda los mensajes que "envió", o tal vez solo la cantidad de mensajes que "envió".

Aquí estamos hablando de simulacros : objetos preprogramados con expectativas que forman una especificación de las llamadas que se espera que reciban.

Desde xunitpattern :

Fake : Adquirimos o construimos una implementación muy liviana de la misma funcionalidad que proporciona un componente del cual depende el SUT e instruimos al SUT para que lo use en lugar del real.

Stub : esta implementación está configurada para responder a las llamadas del SUT con los valores (o excepciones) que ejercerán el Código no probado (ver Errores de producción en la página X) dentro del SUT. Una indicación clave para usar un talón de prueba es tener un código no probado causado por la incapacidad de controlar las entradas indirectas del SUT

Objeto simulado que implementa la misma interfaz que un objeto del que depende el SUT (Sistema bajo prueba). Podemos usar un objeto simulado como un punto de observación cuando necesitamos realizar una verificación de comportamiento para evitar tener un requisito no probado (ver Errores de producción en la página X) causado por la incapacidad de observar los efectos secundarios de los métodos de invocación en el SUT.

Personalmente

Intento simplificar usando: Mock y Stub. Uso Mock cuando es un objeto que devuelve un valor que se establece en la clase probada. Utilizo Stub para imitar una interfaz o clase abstracta para ser probado. De hecho, realmente no importa cómo lo llames, son todas las clases que no se usan en producción y se usan como clases de utilidad para las pruebas.


Se trata de hacer las pruebas expresivas. Fijo expectativas en una simulación si quiero que la prueba describa una relación entre dos objetos. Apago valores de retorno si estoy configurando un objeto de soporte para que me muestre el comportamiento interesante de la prueba.


Si está familiarizado con Arrange-Act-Assert, entonces una forma de explicar la diferencia entre stub y mock que podría ser útil para usted, es que los stubs pertenezcan a la sección de arreglos, ya que son para organizar el estado de entrada, y los mockes pertenecen a La sección de afirmación como son para afirmar los resultados en contra.

Los maniquíes no hacen nada. Son solo para llenar listas de parámetros, para que no se obtengan errores indefinidos o nulos. También existen para satisfacer el comprobador de tipos en idiomas estrictamente escritos, de modo que se le permita compilar y ejecutar.


Stub : un objeto que proporciona respuestas predefinidas a las llamadas a métodos.

Simulacro - un objeto en el que se establecen expectativas.

Fake : un objeto con capacidades limitadas (para fines de prueba), por ejemplo, un servicio web falso.

Prueba doble es el término general para colillas, simulacros y falsificaciones. Pero de manera informal, a menudo oirás que la gente simplemente los llama burlados.