Sé cómo uso estos términos, pero me pregunto si hay definiciones aceptadas para falsificar , burlarse y tropezar para las pruebas unitarias. ¿Cómo los define para sus pruebas? Describa situaciones en las que podría usar cada una.
Así es como los uso:
Falso : una clase que implementa una interfaz pero contiene datos fijos y no tiene lógica. Simplemente devuelve datos "buenos" o "malos" dependiendo de la implementación.
Mock : 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 llamados a métodos particulares.
Talón : como una clase simulada, excepto que no proporciona la capacidad de verificar que los métodos hayan sido llamados / no llamados.
Los simulacros y los talones pueden generarse a mano o generarse mediante un marco de imitación. Las clases falsas se generan a mano. Utilizo 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 dependencias de datos o cuando los simulacros / stubs son demasiado tediosos para configurar cada vez.
fuente
Respuestas:
Puedes obtener alguna información:
De Martin Fowler sobre Mock and Stub
Los objetos falsos en realidad tienen implementaciones que funcionan, pero generalmente toman un atajo que los hace no adecuados para la producción
Los talones proporcionan respuestas enlatadas a las llamadas realizadas durante la prueba, por lo general no responden en absoluto a nada fuera de lo programado para la prueba. Los resguardos también pueden registrar información sobre llamadas, como un resguardo de puerta de enlace 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 :
Falso : Adquirimos o construimos una implementación muy ligera de la misma funcionalidad proporcionada por un componente del que depende el SUT e instruimos al SUT para que lo use en lugar del real.
Stub : esta implementación está configurada para responder a 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 Stub 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 punto de observación cuando necesitamos hacer 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 invocar métodos en el SUT.
Personalmente
Intento simplificar usando: Mock and Stub. Uso Mock cuando es un objeto que devuelve un valor que se establece en la clase probada. Uso Stub para imitar una interfaz o una clase abstracta para probar. De hecho, 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 pruebas.
fuente
Stub : un objeto que proporciona respuestas predefinidas a llamadas a métodos.
Mock : un objeto en el que estableces expectativas.
Falso : un objeto con capacidades limitadas (para fines de prueba), por ejemplo, un servicio web falso.
Test Double es el término general para talones, simulacros y falsificaciones. Pero informalmente, a menudo escuchará a la gente simplemente llamarlos simulacros.
fuente
EXPECT_CALL()
s en un método simulado que fuerce ciertas salidas basadas en ciertas entradas, usando el tipo.WillOnce(Invoke(my_func_or_lambda_func))
(o con.WillRepeatedly()
) sintaxis adjunta a unEXPECT_CALL()
. Algunos ejemplos de usoInvoke()
se pueden ver en un contexto diferente al final de mi larga respuesta aquí: stackoverflow.com/a/60905880/4561887 .Invoke()
está aquí: github.com/google/googletest/blob/master/googlemock/docs/… . De todos modos, la conclusión es: el simulacro de Google (gmock) permite crear fácilmente simulacros y talones , aunque la mayoría de los simulacros no son talones.Me sorprende que esta pregunta haya existido durante tanto tiempo y que nadie haya brindado una respuesta basada en "The Art of Unit Testing" de Roy Osherove. .
En "3.1 Introducción de apéndices" se define un apéndice como:
Y define la diferencia entre stubs y simulacros como:
Falso es solo el nombre que se usa tanto para los trozos como para las simulaciones. Por ejemplo, cuando no te importa la distinción entre trozos y simulacros.
La forma en que Osherove distingue entre trozos y simulacros significa que cualquier clase utilizada como falso para la prueba puede ser tanto un trozo como un simulacro. Lo que es para una prueba específica depende completamente de cómo escriba los cheques en su prueba.
Ejemplo de una prueba donde la clase FakeX se usa como un trozo:
La
fake
instancia se usa como un código auxiliar porqueAssert
no se usafake
en absoluto.Ejemplo de una prueba donde la clase de prueba X se usa como un simulacro:
En este caso,
Assert
comprueba un valorfake
, lo que hace que sea falso.Ahora, por supuesto, estos ejemplos son muy artificiales, pero veo un gran mérito en esta distinción. Te hace saber cómo estás probando tus cosas y dónde están las dependencias de tu prueba.
Estoy de acuerdo con Osherove que
Afirmar lo falso es algo que realmente desea evitar, ya que sus pruebas dependen en gran medida de la implementación de una clase que no es la que se está probando en absoluto. Lo que significa que las pruebas para la clase
ActualClassUnderTest
pueden comenzar a romperse porque la implementación deClassUsedAsMock
cambió. Y eso me envía un olor desagradable. Las pruebas paraActualClassUnderTest
preferiblemente solo deben romperse cuandoActualClassUnderTest
se cambia.Me doy cuenta de que escribir afirmaciones falsas es una práctica común, especialmente cuando eres un suscriptor de TDD falso. Supongo que estoy firmemente con Martin Fowler en el campo clasicista (Ver "Las burlas de Martin Fowler no son trozos" ) y, al igual que Osherove, evito las pruebas de interacción (que solo se pueden hacer afirmando contra lo falso) tanto como sea posible.
Para divertirse leyendo sobre por qué debería evitar los simulacros como se define aquí, busque "clasicista simulador de cazadores". Encontrarás una gran cantidad de opiniones.
fuente
Como se menciona en la respuesta más votada, Martin Fowler analiza estas distinciones en Mocks An't Stubs , y en particular el subtítulo La diferencia entre simulacros y stubs , así que asegúrese de leer ese artículo.
En lugar de centrarnos en cómo estas cosas son diferentes, creo que es más esclarecedor centrarse en por qué estos son conceptos distintos. Cada uno existe para un propósito diferente.
Falsificaciones
Un falso es una implementación que se comporta "naturalmente", pero no es "real". Estos son conceptos confusos, por lo que diferentes personas tienen diferentes interpretaciones de lo que hace que las cosas sean falsas.
Un ejemplo de una falsificación es una base de datos en memoria (por ejemplo, usando sqlite con la
:memory:
tienda). Nunca usaría esto para la producción (ya que los datos no son persistentes), pero es perfectamente adecuado como base de datos para usar en un entorno de prueba. También es mucho más ligero que una base de datos "real".Como otro ejemplo, quizás use algún tipo de almacén de objetos (por ejemplo, Amazon S3) en producción, pero en una prueba simplemente puede guardar objetos en archivos en el disco; entonces su implementación de "guardar en disco" sería falsa. (O incluso podría simular la operación "guardar en disco" utilizando un sistema de archivos en memoria).
Como tercer ejemplo, imagine un objeto que proporciona una API de caché; un objeto que implementa la interfaz correcta pero que simplemente no realiza almacenamiento en caché pero siempre devuelve un error de caché sería una especie de falso.
El propósito de una falsificación no es afectar el comportamiento del sistema bajo prueba , sino más bien simplificar la implementación de la prueba (eliminando las dependencias innecesarias o pesadas).
Trozos
Un trozo es una implementación que se comporta "de forma no natural". Está preconfigurado (generalmente por la configuración de prueba) para responder a entradas específicas con salidas específicas.
El propósito de un código auxiliar es poner su sistema a prueba en un estado específico. Por ejemplo, si está escribiendo una prueba para algún código que interactúa con una API REST, puede desactivar la API REST con una API que siempre devuelve una respuesta fija, o que responde a una solicitud de API con un error específico. De esta manera, podría escribir pruebas que hagan afirmaciones sobre cómo reacciona el sistema a estos estados; por ejemplo, probando la respuesta que obtienen sus usuarios si la API devuelve un error 404.
Un trozo generalmente se implementa para responder solo a las interacciones exactas a las que le has dicho que responda. Pero la característica clave que hace que algo sea un trozo es su propósito : un trozo se trata de configurar su caso de prueba.
Simulacros
Un simulacro es similar a un código auxiliar, pero con la verificación agregada. El propósito de un simulacro es hacer afirmaciones sobre cómo su sistema bajo prueba interactúa con la dependencia .
Por ejemplo, si está escribiendo una prueba para un sistema que carga archivos en un sitio web, puede crear un simulacro que acepte un archivo y que pueda usar para afirmar que el archivo cargado es correcto. O, en una escala más pequeña, es común usar una simulación de un objeto para verificar que el sistema bajo prueba llama a métodos específicos del objeto simulado.
Los simulacros están vinculados a las pruebas de interacción , que es una metodología de prueba específica. Las personas que prefieren probar el estado del sistema en lugar de las interacciones del sistema usarán simulacros con moderación si es que lo hacen.
Prueba doble
Falsificaciones, talones y simulacros pertenecen a la categoría de dobles de prueba . Una prueba doble es cualquier objeto o sistema que usa en una prueba en lugar de otra cosa. La mayoría de las pruebas de software automatizadas implican el uso de dobles de prueba de algún tipo u otro. Algunos otros tipos de dobles prueba incluyen valores ficticios , espías , y de E / S de los agujeros negros .
fuente
Para ilustrar el uso de trozos y simulacros, me gustaría incluir también un ejemplo basado en " The Art of Unit Testing " 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 arroja 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:
¿Cómo prueba que LogAnalyzer llama al servicio de correo electrónico correctamente cuando el servicio web arroja una excepción? Estas son las preguntas que enfrentamos:
¿Cómo podemos reemplazar el servicio web?
¿Cómo podemos simular una excepción del servicio web para que podamos 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 ocuparnos de las dos primeras preguntas utilizando un código auxiliar para el servicio web . Para resolver el tercer problema, podemos usar un objeto simulado para el servicio de correo electrónico .
Un falso es un término genérico que se puede usar para describir un trozo o un simulacro. En nuestra prueba, tendremos dos falsificaciones. Uno será el simulacro del servicio de correo electrónico, que usaremos para verificar que se enviaron los parámetros correctos al servicio de correo electrónico. El otro será un trozo que usaremos para simular una excepción lanzada desde el servicio web. Es un trozo porque no utilizaremos 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 en su contra que se llamó correctamente.
fuente
lo que afirmas sobre él, se llama un objeto simulado y todo lo demás que solo ayudó a ejecutar la prueba, es un trozo .
fuente
Se trata de hacer que las pruebas sean expresivas. Establezco expectativas en un simulacro si quiero que la prueba describa una relación entre dos objetos. Resto los valores de retorno si estoy configurando un objeto de soporte para llevarme al comportamiento interesante en la prueba.
fuente
Si está familiarizado con Arrange-Act-Assert, entonces una forma de explicar la diferencia entre stub y simulacro que podría ser útil para usted es que los stubs pertenecen a la sección de arreglos, como lo son para organizar el estado de entrada, y los simulacros pertenecen a la sección de afirmación como lo son para afirmar resultados contra.
Los tontos no hacen nada. Son solo para llenar listas de parámetros, para que no obtenga errores indefinidos o nulos. También existen para satisfacer el verificador de tipo en idiomas estrictamente escritos, de modo que se le permita compilar y ejecutar.
fuente
Stub, Fakes y Mocks tienen diferentes significados en diferentes fuentes. Le sugiero que presente los términos internos de su equipo y acuerde su significado.
Creo que es importante distinguir entre dos enfoques: - validación de comportamiento (implica sustitución de comportamiento) - validación de estado final (implica emulación de comportamiento)
Considere enviar correos electrónicos en caso de error. Cuando se realiza la validación de la conducta - comprobar que el método
Send
deIEmailSender
fue ejecutado una vez. Y debe emular el resultado de retorno de este método, el Id de retorno del mensaje enviado. Entonces usted dice: "Espero queSend
se llame. Y simplemente devolveré una identificación ficticia (o aleatoria) para cualquier llamada" . Esta es la validación del comportamiento:emailSender.Expect(es=>es.Send(anyThing)).Return((subject,body) => "dummyId")
Al realizar la validación de estado, deberá crear
TestEmailSender
esos implementosIEmailSender
. E implemente elSend
método: guardando la entrada en alguna estructura de datos que se utilizará para la verificación del estado futuro como la matriz de algunos objetosSentEmails
y luego comprueba que verificará queSentEmails
contiene el correo electrónico esperado. Esta es la validación de estado:Assert.AreEqual(1, emailSender.SentEmails.Count)
De mis lecturas entendí que la validación de comportamiento generalmente se llamaba simulacros . Y la validación estatal generalmente se llama Stubs o Fakes .
fuente
stub y fake son objetos en el sentido de que pueden variar su respuesta en función de los parámetros de entrada. La principal diferencia entre ellos es que un Fake está más cerca de una implementación en el mundo real que un trozo. Los apéndices contienen básicamente respuestas codificadas a una solicitud esperada. Veamos un ejemplo:
Un simulacro es un paso adelante de las falsificaciones y los trozos. Los simulacros proporcionan la misma funcionalidad que los apéndices, pero son más complejos. Pueden tener reglas definidas para ellos que dictan en qué orden deben llamarse los métodos en su API. La mayoría de los simulacros pueden rastrear cuántas veces se llamó a un método y pueden reaccionar en función de esa información. Los simulacros generalmente conocen el contexto de cada llamada y pueden reaccionar de manera diferente en diferentes situaciones. Debido a esto, los simulacros requieren algún conocimiento de la clase de la que se burlan. un trozo generalmente no puede rastrear cuántas veces se llamó a un método o en qué orden se llamó a una secuencia de métodos. Un simulacro se parece a:
fuente
fake object
es una implementación real de interfaz (protocolo) o una extensión que usa herencia u otros enfoques que se pueden usar para crear, es la dependencia. Por lo general, el desarrollador lo crea como una solución más simple para sustituir alguna dependenciastub object
Es un objeto desnudo (0, nil y métodos sin lógica) con y extra y predefinida (por desarrollador) estado para definir valores devueltos. Por lo general, es creado por frameworkmock object
es muy similarstub object
pero se cambia el estado adicional durante la ejecución del programa para verificar si sucedió algo (se llamó al método).fuente