¿Qué es burlarse?

Respuestas:

599

Prólogo: si buscas el nombre simulado en el diccionario, encontrarás que una de las definiciones de la palabra es algo hecho como una imitación .


La burla se usa principalmente en pruebas unitarias. Un objeto bajo prueba puede tener dependencias de otros objetos (complejos). Para aislar el comportamiento del objeto, desea reemplazar los otros objetos por simulacros que simulan el comportamiento de los objetos reales. Esto es útil si los objetos reales no son prácticos para incorporar en la prueba unitaria.

En resumen, burlarse es crear objetos que simulan el comportamiento de objetos reales.


A veces es posible que desee distinguir entre burlarse en lugar de tropezar . Puede haber algún desacuerdo sobre este tema, pero mi definición de un trozo es un objeto simulado "mínimo". El código auxiliar implementa el comportamiento suficiente para permitir que el objeto bajo prueba ejecute la prueba.

Un simulacro es como un trozo, pero la prueba también verificará que el objeto bajo prueba llame al simulacro como se esperaba. Parte de la prueba es verificar que el simulacro se usó correctamente.

Para dar un ejemplo: puede colocar una base de datos al implementar una estructura simple en memoria para almacenar registros. El objeto bajo prueba puede leer y escribir registros en el código auxiliar de la base de datos para permitirle ejecutar la prueba. Esto podría probar algún comportamiento del objeto no relacionado con la base de datos y el código auxiliar de la base de datos se incluiría solo para permitir que se ejecute la prueba.

Si, en cambio, desea verificar que el objeto bajo prueba escribe algunos datos específicos en la base de datos, tendrá que burlarse de la base de datos. Su prueba luego incorporaría afirmaciones sobre lo que se escribió en la simulación de la base de datos.

Martin Liversage
fuente
18
Esta es una buena respuesta, pero restringe innecesariamente el concepto de burlarse de los objetos . Reemplazar "objeto" con "unidad" lo haría más general.
Rogério
1
Entiendo la diferencia de stub vs. simulacro. Lo único es que si está probando sus casos con un talón y pasa, ¿no puede concluir que ya está utilizando el talón, por lo que ya no necesita la verificación ?
Miel
91

Otras respuestas explican lo que es burlarse. Déjame guiarte con diferentes ejemplos . Y créeme, en realidad es mucho más simple de lo que piensas.

tl; dr Es una instancia de la clase original. Tiene otros datos inyectados para que evite probar las partes inyectadas y se centre únicamente en probar los detalles de implementación de su clase / funciones.

Un simple ejemplo:

class Foo {
    func add (num1: Int, num2: Int) -> Int { // Line A 
        return num1 + num2 // Line B
    }
}

let unit = Foo() // unit under test
assertEqual(unit.add(1,5),6)

Como puede ver, no estoy probando LineA, es decir, no estoy validando los parámetros de entrada. No estoy validando para ver si num1, num2 son un número entero. No tengo afirmaciones en contra de eso.

Solo estoy probando para ver si LineB (mi implementación ) da los valores simulados 1y 5está haciendo lo que esperaba.

Obviamente, en la palabra real, esto puede volverse mucho más complejo. Los parámetros pueden ser un objeto personalizado como una Persona, Dirección, o los detalles de implementación pueden ser más de uno +. Pero la lógica de las pruebas sería la misma.

Ejemplo de no codificación:

Suponga que está construyendo una máquina que identifica el tipo y la marca de los dispositivos electrónicos para la seguridad de un aeropuerto. La máquina hace esto procesando lo que ve con su cámara.

Ahora su gerente entra por la puerta y le pide que lo pruebe en la unidad.

Luego, como desarrollador, puede traer 1000 objetos reales, como un MacBook pro, Google Nexus, un plátano, un iPad, etc. delante y probar y ver si todo funciona.

Pero también puede usar objetos burlados , como un MacBook pro de aspecto idéntico (sin partes internas reales) o un plátano de plástico frente a él. Puede ahorrarse de invertir en 1000 computadoras portátiles reales y plátanos podridos.

El punto es que no estás tratando de probar si el plátano es falso o no. Tampoco probar si la computadora portátil es falsa o no. Todo lo que estamos haciendo es probar si su máquina una vez que se ve un plátano que diría not an electronic devicey por un MacBook Pro que diría: Laptop, Apple. Para la máquina, el resultado de su detección debe ser el mismo para la electrónica falsa / burlada y la electrónica real

La lógica mencionada anteriormente se aplica también a las pruebas unitarias del código real. Esa es una función que debería funcionar de la misma manera con los valores reales que obtienes de la entrada real (y las interacciones) o burladosvalores que inyecta durante las pruebas unitarias. Y de la misma manera en que se ahorra el uso de una banana real o una MacBook, con pruebas unitarias (y burlas) se ahorra tener que hacer algo que haga que su servidor devuelva un código de estado de 500, 403, 200, etc. (forzando su servidor para activar 500 es solo cuando el servidor está inactivo, mientras que 200 es cuando el servidor está activo. Se hace difícil ejecutar 100 pruebas centradas en la red si tiene que esperar constantemente 10 segundos entre el cambio de servidor hacia arriba y hacia abajo). Entonces, en su lugar, inyecta / se burla de una respuesta con el código de estado 500, 200, 403, etc. y prueba su unidad / función con un valor inyectado / burlado.

Ejemplo de codificación:

Supongamos que está escribiendo una aplicación para iOS y tiene llamadas de red. Su trabajo es probar su aplicación. Probar / identificar si las llamadas de red funcionan o no como se espera NO ES SU RESPONSABILIDAD. Es responsabilidad de otra parte (equipo del servidor) probarlo. Debe eliminar esta dependencia (de red) y, sin embargo, continuar probando todo el código que funciona a su alrededor .

Una llamada de red puede devolver diferentes códigos de estado 404, 500, 200, 303, etc. con una respuesta JSON.

Se supone que su aplicación funciona para todos ellos (en caso de errores, su aplicación debería arrojar el error esperado). Lo que hace con burlarse es crear respuestas de red 'imaginarias, similares a las reales' (como un código 200 con un archivo JSON) y probar su código sin 'hacer la llamada de red real y esperar su respuesta de red'. Usted codifica / devuelve manualmente la respuesta de red para TODOS los tipos de respuestas de red y comprueba si su aplicación funciona como espera. ( nunca asume / prueba un 200 con datos incorrectos, porque esa no es su responsabilidad, su responsabilidad es probar su aplicación con un 200 correcto, o en el caso de un 400, 500, prueba si su aplicación arroja el error correcto)

Esta creación imaginaria, similar a la real, se conoce como burla.

Para hacer esto, no puede usar su código original (su código original no tiene las respuestas previamente insertadas, ¿verdad?). Usted debe agregar algo a ella, inyecte / insertar datos ficticios que los que normalmente no se necesitan (o una parte de su clase).

Entonces, crea una instancia de la clase original y agrega lo que sea (aquí es la red HTTPResponse, datos O en el caso de falla, le pasa el errorString correcto, HTTPResponse) que necesita y luego prueba la clase burlada .

En pocas palabras, burlarse es simplificar y limitar lo que está probando y también hacer que alimente de lo que depende una clase. En este ejemplo, evita probar las llamadas de la red y, en cambio, prueba si su aplicación funciona o no como espera con las salidas / respuestas inyectadas , burlándose de las clases

No hace falta decir que prueba cada respuesta de red por separado.


Ahora, una pregunta que siempre tuve en mente fue: Los contratos / puntos finales y básicamente la respuesta JSON de mis API se actualizan constantemente. ¿Cómo puedo escribir pruebas unitarias que tengan esto en cuenta?

Para elaborar más sobre esto: digamos que el modelo requiere una clave / campo llamado username. Usted prueba esto y su prueba pasa. 2 semanas después, el backend cambia el nombre de la clave a id. Tus pruebas aún pasan. ¿Correcto? ¿o no?

¿Es responsabilidad del desarrollador del backend actualizar los simulacros? ¿Debería ser parte de nuestro acuerdo que proporcionen simulacros actualizados?

La respuesta al problema anterior es que: las pruebas unitarias + su proceso de desarrollo como desarrollador del lado del cliente deberían / ​​podrían detectar una respuesta simulada obsoleta. Si me preguntas cómo? bueno la respuesta es:

Nuestra aplicación real fallaría (o no fallaría aún sin tener el comportamiento deseado) sin usar API actualizadas ... por lo tanto, si eso falla ... haremos cambios en nuestro código de desarrollo. Lo que nuevamente lleva a que nuestras pruebas fallen ... y tendremos que corregirlo. (En realidad, si vamos a hacer el proceso TDD correctamente, no debemos escribir ningún código sobre el campo a menos que escribamos la prueba para él ... y veamos que falla y luego vamos y escribimos el código de desarrollo real para él).

Todo esto significa que el backend no tiene que decir: "oye, actualizamos los simulacros" ... eventualmente sucede a través del desarrollo / depuración de su código. ‌ّ ¡Porque todo es parte del proceso de desarrollo! Aunque si el backend proporciona la respuesta burlada para usted, entonces es más fácil.

Todo mi punto sobre esto es que (si no puede automatizar la actualización de la respuesta de API simulada ), se requiere cierta interacción humana, es decir, actualizaciones manuales de JSON y reuniones cortas para asegurarse de que sus valores estén actualizados formarán parte de su proceso

Esta sección fue escrita gracias a una discusión floja en nuestro grupo de reunión CocoaHead


Solo para desarrolladores de iOS:

Un muy buen ejemplo de burla es esta charla práctica orientada al protocolo de Natasha Muraschev . Simplemente pase al minuto 18:30, aunque las diapositivas pueden no estar sincronizadas con el video real 🤷‍♂️

Realmente me gusta esta parte de la transcripción:

Debido a que esto es una prueba ... queremos asegurarnos de que se llame a la getfunción desde Gettable, porque puede regresar y, en teoría, la función podría asignar una variedad de alimentos desde cualquier lugar . Necesitamos asegurarnos de que se llame;

Miel
fuente
3
Gran ejemplo, solo agregaría que en este ejemplo en particular la subclase actúa como simulacro, pero este ejemplo también usa stubbing. Las respuestas JSON codificadas se consideran respuestas tropezadas. Solo agrego esto porque puede ser difícil diferenciar entre simulacros y trozos, pero este ejemplo muestra claramente cómo ambos se pueden usar juntos.
user3344977
Excelente explicación, gracias. Un pequeño ajuste a la pregunta sobre el cambio de API. ¿Qué pasa si no es tu API y no eres parte del proceso de desarrollo? Quiero saber cuándo falla la biblioteca de mi cliente.
ThinkDigital
@ThinkDigital Los buenos proveedores de API tienen buenas notas de lanzamiento y comunican los cambios correctamente, si no tiene ese canal, entonces tal vez sea hora de que se siente en una reunión y lo discuta | los buenos desarrolladores siempre buscarán cambios en la API de una nueva versión y evitarán simplemente actualizar la versión de la API. ¿Tienes versiones de API? Si ninguno de los dos lo atrapa, luego de QAing lo descubrirá, luego actualice sus pruebas ← deber de todo el equipo. → deber un solo desarrollador: no debería importarme mucho. Simplemente maneje el caso donde el servidor devuelve el error, o el servidor no devuelve el error pero no puede analizar json, o manejar el caso correcto.
Miel
Gracias por responder, @Honey! En mi caso, mantengo un cliente para pub.dev , que tiene una API, pero le falta mucho. Tanto es así que era mejor hacer una API raspando su sitio, que usar su API oficial. Debido a esto, los cambios en el sitio pueden romper el código y no tendrían necesidad de molestarse en actualizar a nadie en este caso. El sitio es de código abierto, pero es algo diferente mantener una API que se basa en los cambios que se realizan de manera más trivial.
ThinkDigital
32

Hay muchas respuestas sobre SO y buenas publicaciones en la web sobre burlas. Un lugar que es posible que desee empezar a buscar es el mensaje por Martin Fowler Mocks ¿No son Stubs donde discute muchas de las ideas de burla.

En un párrafo: la burla es una técnica particular para permitir la prueba de una unidad de código sin depender de dependencias. En general, lo que diferencia la burla de otros métodos es que los objetos simulados utilizados para reemplazar las dependencias del código permitirán establecer expectativas: un objeto simulado sabrá cómo debe ser llamado por su código y cómo responder.


Su pregunta original mencionaba TypeMock, así que dejé mi respuesta a eso a continuación:

TypeMock es el nombre de un marco comercial burlón .

Ofrece todas las características de los marcos de simulación gratuitos como RhinoMocks y Moq, además de algunas opciones más potentes.

Si necesita o no TypeMock es muy discutible: puede hacer la mayor cantidad de burlas que desee con bibliotecas de burlas gratuitas, y muchos argumentan que las habilidades que ofrece TypeMock a menudo lo alejarán del diseño bien encapsulado.

Como dijo otra respuesta, 'TypeMocking' no es en realidad un concepto definido, pero podría entenderse como el tipo de burla que ofrece TypeMock, utilizando el perfilador CLR para interceptar llamadas .Net en tiempo de ejecución, lo que brinda una capacidad mucho mayor para falsificar objetos (no requisitos como la necesidad de interfaces o métodos virtuales).

David Hall
fuente
@Masoud nunca mencionó TypeMock. Su pregunta era sobre "burlas tipo" en general.
Peter Lillevold
44
@Peter: como decía otro comentario, verifique el historial de edición de la pregunta. No puedo hacer mucho si publico una respuesta y luego la pregunta original cambia por completo.
David Hall
9

Mock es un método / objeto que simula el comportamiento de un método / objeto real de manera controlada. Los objetos simulados se utilizan en pruebas unitarias.

A menudo, un método bajo una prueba llama a otros servicios o métodos externos dentro de él. Estas se llaman dependencias. Una vez burladas, las dependencias se comportan de la forma en que las definimos.

Con las dependencias controladas por simulacros, podemos probar fácilmente el comportamiento del método que codificamos. Esta es la prueba de la Unidad.

¿Cuál es el propósito de los objetos simulados?

Simulacros vs trozos

Pruebas unitarias vs Pruebas funcionales

Venkat Kotra
fuente
7

Burlarse genera pseudoobjetos que simulan el comportamiento de objetos reales para pruebas

Jajaja
fuente
5

El propósito de los tipos de burla es cortar dependencias para aislar la prueba a una unidad específica. Los talones son sustitutos simples, mientras que los simulacros son sustitutos que pueden verificar el uso. Un marco burlón es una herramienta que te ayudará a generar talones y simulaciones.

EDITAR : Dado que la redacción original menciona "burlarse de tipos", tuve la impresión de que esto estaba relacionado con TypeMock. En mi experiencia, el término general es simplemente "burlarse". No dude en ignorar la información a continuación específicamente en TypeMock.

TypeMock Isolator difiere de la mayoría de los demás framework de burla en que funciona modificando mi IL sobre la marcha. Eso le permite simular tipos e instancias que la mayoría de los otros marcos no pueden imitar. Para burlarse de estos tipos / instancias con otros marcos, debe proporcionar sus propias abstracciones y burlarse de ellas.

TypeMock ofrece una gran flexibilidad a expensas de un entorno de tiempo de ejecución limpio. Como efecto secundario de la forma en que TypeMock logra sus resultados, a veces obtendrá resultados muy extraños al usar TypeMock.

Brian Rasmussen
fuente
@Masoud nunca mencionó TypeMock. Su pregunta era sobre "burlas tipo" en general.
Peter Lillevold
1
@Peter: La redacción original era "¿qué es el tipo burlón?".
Brian Rasmussen
Lo sé. Dado que "burlarse de tipo" no es equivalente a "TypeMock", encuentro que tanto la respuesta suya como la de @Oded están fuera de lugar.
Peter Lillevold
1
@ Peter: En mi experiencia, el término general es "burlarse", pero en cualquier caso he actualizado mi respuesta para que quede claro. Gracias por el aporte.
Brian Rasmussen
3

Creo que el uso del marco de imitación del aislador TypeMock sería TypeMocking.

Es una herramienta que genera simulacros para su uso en pruebas unitarias, sin la necesidad de escribir su código con IoC en mente.

Oded
fuente
@Masoud nunca mencionó TypeMock. Su pregunta era sobre "burlas tipo" en general.
Peter Lillevold
3
En realidad, la pregunta original incluía la palabra "Tipo" antes de "Burlarse", pero luego fue editada. Es por eso que algunas de las respuestas contienen información específica sobre TypeMock.
Martin Liversage
1

Si su simulación involucra una solicitud de red, otra alternativa es tener un servidor de prueba real para acertar. Puede usar este servicio para generar una solicitud y una respuesta para sus pruebas. http://testerurl.com/

foobar8675
fuente
Intenté acceder a él y me tomó varios minutos. ¿Quién puede decir que no está registrando solicitudes en secreto también? Finalmente, esto podría ser mejor como comentario :)
Kieren Johnstone
De hecho, lo eliminé porque no tenía ganas de moverlo a un alojamiento gratuito. Sí, esto debería haber sido un comentario. es de código abierto, por lo que si le preocupa el registro de solicitudes, puede ejecutar el suyo. github.com/captainchung/TesterUrl
Matthew Chung