¿Cuál es la diferencia entre un simulacro y un talón?

He leído varios artículos sobre simulacros y tropezones en las pruebas, incluyendo Mocks Are not Stubs de Martin Fowler , pero aún no entiendo la diferencia.

Talón

Creo que la mayor distinción es un talón que ya has escrito con un comportamiento predeterminado. Por lo tanto, tendría una clase que implemente la dependencia (es decir, la clase abstracta o la interfaz más probable) a la que simule con fines de prueba y los métodos simplemente se anularán con las respuestas establecidas. No harían nada lujoso y ya habrían escrito el código resquebrajado fuera de su prueba.

Burlarse de

Un simulacro es algo que, como parte de su prueba, debe configurar con sus expectativas. Un simulacro no está configurado de manera predeterminada, por lo que tiene un código que lo hace en su prueba. Los simulacros en cierto modo se determinan en tiempo de ejecución ya que el código que establece las expectativas debe ejecutarse antes de que hagan algo.

Diferencia

Las pruebas escritas con burlas generalmente siguen un patrón de initialize -> set expectations -> exercise -> verify para probar. Mientras que el stub preescrito seguiría un initialize -> exercise -> verify .

Semejanza

El propósito de ambos es eliminar la prueba de todas las dependencias de una clase o función para que sus pruebas estén más centradas y sean más simples en lo que intentan probar.

Prefacio

Hay varias definiciones de objetos, que no son reales. El término general es prueba doble . Este término abarca: dummy , fake , stub , mock .

Referencia

De acuerdo con el artículo de Martin Fowler :

  • Los objetos ficticios se pasan pero nunca se usan realmente. Por lo general, solo se utilizan para llenar listas de parámetros.
  • Los objetos falsos en realidad tienen implementaciones que funcionan, pero generalmente toman algún atajo que los hace inadecuados para la producción (una base de datos en la memoria es un buen ejemplo).
  • Los talones brindan respuestas predefinidas a las llamadas realizadas durante la prueba, por lo general no responden a nada fuera de lo progtwigdo para la prueba. Los talones también pueden registrar información sobre llamadas, como un talón de la puerta de enlace de correo electrónico que recuerda los mensajes que ‘envió’, o tal vez solo la cantidad de mensajes que ‘envió’.
  • A eso nos referimos con burlas: objetos preprogtwigdos con expectativas que forman una especificación de las llamadas que se espera que reciban.

Estilo

Mocks vs Stubs = Pruebas de comportamiento frente a pruebas estatales

Principio

De acuerdo con el principio de probar solo una cosa por prueba , puede haber varios talones en una prueba, pero generalmente solo hay una simulación.

Ciclo vital

Ciclo de vida de la prueba con talones:

  1. Configuración – Prepare el objeto que se está probando y sus colgantes colaboradores.
  2. Ejercicio: prueba la funcionalidad.
  3. Verificar estado: use afirma para verificar el estado del objeto.
  4. Desassembly: limpiar los recursos.

Prueba de ciclo de vida con simulacros:

  1. Datos de configuración: prepare el objeto que se está probando.
  2. Configure las expectativas : prepare expectativas en el simulacro que está siendo utilizado por el objeto primario.
  3. Ejercicio: prueba la funcionalidad.
  4. Verificar las expectativas : verificar que se hayan invocado los métodos correctos en el simulacro.
  5. Verificar estado: use afirma para verificar el estado del objeto.
  6. Desassembly: limpiar los recursos.

Resumen

Las pruebas de simulacros y trozos brindan una respuesta a la pregunta: ¿Cuál es el resultado?

Las pruebas con simulacros también están interesados ​​en: ¿Cómo se ha logrado el resultado?

Stub es un simple objeto falso. Solo hace que la prueba funcione sin problemas.
Mock es un trozo más inteligente. Usted verifica que su prueba pasa a través de él.

Aquí hay una descripción de cada uno seguido de una muestra del mundo real.

  • Dummy : solo valores falsos para satisfacer la API .

    Ejemplo : Si está probando un método de una clase que requiere muchos parámetros obligatorios en un constructor que no tienen ningún efecto en su prueba, entonces puede crear objetos ficticios con el fin de crear nuevas instancias de una clase.

  • Fake : crea una implementación de prueba de una clase que puede tener una dependencia en alguna infraestructura externa. (Es una buena práctica que la prueba de su unidad NO interactúe con la infraestructura externa).

    Ejemplo : cree una implementación falsa para acceder a una base de datos, reemplácela con in-memory colección in-memory .

  • Stub : anula los métodos para devolver valores codificados, también conocidos como state-based .

    Ejemplo : Su clase de prueba depende de un método Calculate() tarda 5 minutos en completarse. En lugar de esperar 5 minutos, puede reemplazar su implementación real con un código que devuelve valores codificados; tomando solo una pequeña fracción del tiempo.

  • Mock : muy similar a Stub pero interaction-based en interaction-based lugar de interaction-based en estado. Esto significa que no espera que Mock devuelva algún valor, sino que suponga que se realiza un orden específico de llamadas a métodos.

    Ejemplo: estás probando una clase de registro de usuario. Después de llamar a Save , debe llamar a SendConfirmationEmail .

Stubs y Mocks son en realidad sub tipos de Mock , ambos intercambian la implementación real con la implementación de prueba, pero por razones diferentes y específicas.

En el curso codeschool.com , Rails Testing for Zombies , dan esta definición de los términos:

Talón

Para reemplazar un método con código que devuelve un resultado especificado.

Burlarse de

Un apéndice con una afirmación de que se llama al método.

Entonces, como describió Sean Copenhaver en su respuesta, la diferencia es que los simulacros establecen expectativas (es decir, hacen afirmaciones sobre si se les llama o cómo se llaman).

Los talones no fallan en sus pruebas, simulacro.

Creo que la respuesta más simple y clara sobre esta pregunta viene dada por Roy Osherove en su libro The art of Unit Testing (página 85)

La manera más fácil de decir que estamos tratando con un código auxiliar es observar que el código auxiliar nunca puede fallar la prueba. Afirma que los usos de la prueba siempre están en contra de la clase bajo prueba.

Por otro lado, la prueba usará un objeto simulado para verificar si la prueba falló o no. […]

De nuevo, el objeto simulado es el objeto que usamos para ver si la prueba falló o no.

Eso significa que si estás haciendo afirmaciones contra el falso, significa que estás usando el falso como un simulacro, si usas el falso solo para ejecutar la prueba sin afirmarlo, estás usando el falso como un stub.

Creo que la diferencia más importante entre ellos es sus intenciones.

Déjame tratar de explicarlo en POR QUÉ stub vs. WHY se burlan

Supongamos que estoy escribiendo un código de prueba para el controlador de línea de tiempo público de mi cliente de mac twitter

Aquí está el código de muestra de prueba

 twitter_api.stub(:public_timeline).and_return(public_timeline_array) client_ui.should_receive(:insert_timeline_above).with(public_timeline_array) controller.refresh_public_timeline 
  • STUB: la conexión de red a Twitter API es muy lenta, lo que hace que mi prueba sea lenta. Sé que devolverá las líneas de tiempo, así que hice un apéndice que simula la API HTTP de Twitter, de modo que mi prueba se ejecutará muy rápido, y puedo ejecutar la prueba incluso cuando estoy desconectado.
  • MOCK: Todavía no he escrito ninguno de mis métodos de UI, y no estoy seguro de qué métodos necesito para escribir en mi objeto ui. Espero saber cómo mi controlador colaborará con mi objeto ui al escribir el código de prueba.

Al escribir simulacro, descubre la relación de colaboración de los objetos verificando que se cumplen las expectativas, mientras que el apéndice solo simula el comportamiento del objeto.

Le sugiero que lea este artículo si está tratando de saber más acerca de los simulacros: http://jmock.org/oopsla2004.pdf

Un simulacro simplemente está probando el comportamiento, asegurándose de que se invocan ciertos métodos. Un Stub es una versión comprobable (per se) de un objeto en particular.

¿Qué quieres decir con una forma de Apple?

Si lo comparas con la depuración:

Stub es como asegurarse de que un método devuelve el valor correcto

El simulacro es como entrar en el método y asegurarse de que todo lo que está adentro sea correcto antes de devolver el valor correcto.

Para ser muy claro y práctico:

Stub: Una clase u objeto que implementa los métodos de la clase / objeto que se va a falsificar y devuelve siempre lo que desea.

Ejemplo en JavaScript:

 var Stub = { method_a: function(param_a, param_b){ return 'This is an static result'; } } 

Mock: Lo mismo de stub, pero agrega algo de lógica que “verifica” cuando se llama un método, por lo que puede estar seguro de que alguna implementación llama a ese método.

Como @mLevan dice imagina como ejemplo que estás probando una clase de registro de usuario. Después de llamar a Guardar, debe llamar a SendConfirmationEmail.

Un ejemplo de código muy estúpido:

 var Mock = { calls: { method_a: 0 } method_a: function(param_a, param_b){ this.method_a++; console.log('Mock.method_a its been called!'); } } 

Me gusta la explicación expuesta por Roy Osherove [video link] .

Cada clase u objeto creado es falso. Es un simulacro si verifica las llamadas en su contra. De lo contrario, es un trozo.

Leyendo todas las explicaciones anteriores, permítanme intentar condensar:

  • Stub : una pieza falsa de código que permite ejecutar la prueba, pero no le importa lo que le suceda.
  • Simulacro : una pieza de código ficticia, que VERIFICAR se llama correctamente como parte de la prueba.
  • Spy : un código ficticio que intercepta algunas llamadas a un código real, lo que le permite verificar llamadas sin reemplazar todo el objeto original.

Un falso es un término genérico que se puede utilizar para describir un trozo o un objeto simulado (escrito a mano o de otro modo), ya que ambos se parecen al objeto real.

Si un falso es un stub o un simulacro depende de cómo se usa en la prueba actual. Si se usa para verificar una interacción (afirmado en contra), es un objeto simulado. De lo contrario, es un trozo.

Fakes se asegura de que la prueba funcione sin problemas. Significa que el lector de su prueba futura comprenderá cuál será el comportamiento del objeto falso, sin necesidad de leer su código fuente (sin necesidad de depender de un recurso externo).

¿Qué significa la prueba sin problemas?
Por ejemplo, en el siguiente código:

  public void Analyze(string filename) { if(filename.Length<8) { try { errorService.LogError("long file entered named:" + filename); } catch (Exception e) { mailService.SendEMail("admin@hotmail.com", "ErrorOnWebService", "someerror"); } } } 

Desea probar el método mailService.SendEMail () , para hacer eso, necesita simular una excepción en su método de prueba, por lo que solo necesita crear una clase de ErrorSub StubService para simular ese resultado, entonces su código de prueba podrá probar método mailService.SendEMail (). Como ve, necesita simular un resultado que proviene de otra clase de Servicio de Error de Dependencia Externa.

Esta diapositiva explica las principales diferencias muy buenas.

enter image description here

* De CSE 403 Conferencia 16, Universidad de Washington (diapositiva creada por “Marty Stepp”)

Desde el papel Mock Roles, no Objects , por los desarrolladores de jMock:

Los stubs son implementaciones ficticias de código de producción que devuelven resultados enlatados. Los objetos simulados actúan como stubs, pero también incluyen aserciones para instrumentar las interacciones del objeto objective con sus vecinos.

Entonces, las principales diferencias son:

  • las expectativas establecidas en los talones suelen ser genéricas, mientras que las expectativas establecidas en los simulacros pueden ser más “inteligentes” (por ejemplo, devolver esto en la primera llamada, esto en la segunda, etc.).
  • Los stubs se usan principalmente para configurar entradas indirectas del SUT , mientras que los simulacros se pueden usar para probar tanto las entradas indirectas como las indirectas del SUT.

En resumen, al mismo tiempo que intentamos dispersar la confusión del título del artículo de Fowler : los simulacros son talones, pero no son solo talones .

  • Trozos vs. Mocks
    • Talones
      1. proporcionar respuestas específicas a las llamadas a métodos
        • ex: myStubbedService.getValues ​​() simplemente devuelve una Cadena necesaria para el código bajo prueba
      2. utilizado por el código bajo prueba para aislarlo
      3. no puede fallar la prueba
        • ex: myStubbedService.getValues ​​() simplemente devuelve el valor resuelto
      4. a menudo implementan métodos abstractos
    • Mocks
      1. “superconjunto” de talones; puede afirmar que se llaman ciertos métodos
        • ej .: verificar que myMockedService.getValues ​​() se invoque solo una vez
      2. utilizado para probar el comportamiento del código bajo prueba
      3. puede fallar la prueba
        • ex: verifica que myMockedService.getValues ​​() se haya llamado una vez; la verificación falla, porque myMockedService.getValues ​​() no fue llamado por mi código probado
      4. a menudo se burla de las interfaces

Vea a continuación el ejemplo de simulaciones versus talones usando C # y Moq framework. Moq no tiene una palabra clave especial para Stub pero también puede usar el objeto Mock para crear stubs.

 namespace UnitTestProject2 { using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; [TestClass] public class UnitTest1 { ///  /// Test using Mock to Verify that GetNameWithPrefix method calls Repository GetName method "once" when Id is greater than Zero ///  [TestMethod] public void GetNameWithPrefix_IdIsTwelve_GetNameCalledOnce() { // Arrange var mockEntityRepository = new Mock(); mockEntityRepository.Setup(m => m.GetName(It.IsAny())); var entity = new EntityClass(mockEntityRepository.Object); // Act var name = entity.GetNameWithPrefix(12); // Assert mockEntityRepository.Verify(m => m.GetName(It.IsAny()), Times.Once); } ///  /// Test using Mock to Verify that GetNameWithPrefix method doesn't call Repository GetName method when Id is Zero ///  [TestMethod] public void GetNameWithPrefix_IdIsZero_GetNameNeverCalled() { // Arrange var mockEntityRepository = new Mock(); mockEntityRepository.Setup(m => m.GetName(It.IsAny())); var entity = new EntityClass(mockEntityRepository.Object); // Act var name = entity.GetNameWithPrefix(0); // Assert mockEntityRepository.Verify(m => m.GetName(It.IsAny()), Times.Never); } ///  /// Test using Stub to Verify that GetNameWithPrefix method returns Name with a Prefix ///  [TestMethod] public void GetNameWithPrefix_IdIsTwelve_ReturnsNameWithPrefix() { // Arrange var stubEntityRepository = new Mock(); stubEntityRepository.Setup(m => m.GetName(It.IsAny())) .Returns("Stub"); const string EXPECTED_NAME_WITH_PREFIX = "Mr. Stub"; var entity = new EntityClass(stubEntityRepository.Object); // Act var name = entity.GetNameWithPrefix(12); // Assert Assert.AreEqual(EXPECTED_NAME_WITH_PREFIX, name); } } public class EntityClass { private IEntityRepository _entityRepository; public EntityClass(IEntityRepository entityRepository) { this._entityRepository = entityRepository; } public string Name { get; set; } public string GetNameWithPrefix(int id) { string name = string.Empty; if (id > 0) { name = this._entityRepository.GetName(id); } return "Mr. " + name; } } public interface IEntityRepository { string GetName(int id); } public class EntityRepository:IEntityRepository { public string GetName(int id) { // Code to connect to DB and get name based on Id return "NameFromDb"; } } } 

Me encontré con este interesante artículo de UncleBob The Little Mocker . Explica toda la terminología de una manera muy fácil de entender, por lo que es útil para principiantes. El artículo de Martin Fowlers es una lectura difícil especialmente para principiantes como yo.

Stub nos ayuda a ejecutar la prueba. ¿Cómo? Da valores que ayudan a ejecutar la prueba. Estos valores en sí mismos no son reales y creamos estos valores solo para ejecutar la prueba. Por ejemplo, creamos un HashMap para darnos valores que son similares a los valores en la tabla de la base de datos. Entonces, en lugar de interactuar directamente con la base de datos, interactuamos con Hashmap.

Mock es un objeto falso que ejecuta la prueba. donde ponemos afirmar.

He usado ejemplos de Python en mi respuesta para ilustrar las diferencias.

Stub – Stubbing es una técnica de desarrollo de software utilizada para implementar métodos de clases al principio del ciclo de vida del desarrollo. Se usan comúnmente como marcadores de posición para la implementación de una interfaz conocida, donde la interfaz está finalizada o es conocida, pero la implementación aún no se conoce o finaliza. Empiezas con stubs, lo que simplemente significa que solo escribes la definición de una función y dejas el código actual para más adelante. La ventaja es que no olvidará los métodos y puede seguir pensando en su diseño mientras lo ve en el código. También puede hacer que su stub devuelva una respuesta estática para que la respuesta pueda ser utilizada por otras partes de su código de inmediato. Los objetos Stub proporcionan una respuesta válida, pero es estática sin importar qué entrada ingrese, siempre obtendrá la misma respuesta:

 class Foo(object): def bar1(self): pass def bar2(self): #or ... raise NotImplementedError def bar3(self): #or return dummy data return "Dummy Data" 

Los objetos simulados se utilizan en casos de prueba simulados que validan que se invocan ciertos métodos sobre esos objetos. Los objetos simulados son objetos simulados que imitan el comportamiento de los objetos reales de forma controlada. Por lo general, crea un objeto simulado para probar el comportamiento de otro objeto. Los simulacros nos permiten simular recursos que no están disponibles o son demasiado difíciles de manejar para las pruebas unitarias.

mymodule.py:

 import os import os.path def rm(filename): if os.path.isfile(filename): os.remove(filename) 

test.py:

 from mymodule import rm import mock import unittest class RmTestCase(unittest.TestCase): @mock.patch('mymodule.os') def test_rm(self, mock_os): rm("any path") # test that rm called os.remove with the right parameters mock_os.remove.assert_called_with("any path") if __name__ == '__main__': unittest.main() 

Este es un ejemplo muy básico que simplemente ejecuta rm y afirma el parámetro con el que fue llamado. Puede usar el simulacro con objetos, no solo las funciones que se muestran aquí, y también puede devolver un valor para que se pueda usar un objeto simulado para reemplazar un talón para probarlo.

Más información sobre unittest.mock , note en python 2.x mock no está incluido en unittest pero es un módulo descargable que se puede descargar a través de pip (pip install simulacro).

También leí “The Art of Unit Testing” (El arte de las pruebas unitarias) de Roy Osherove y creo que sería fantástico que se escribiera un libro similar utilizando ejemplos de Python y Python. Si alguien sabe de un libro así, por favor comparte. Saludos 🙂

Un stub es un objeto falso creado para fines de prueba. Un simulacro es un talón que registra si las llamadas esperadas ocurrieron efectivamente.

Un stub es una función vacía que se usa para evitar excepciones no controladas durante las pruebas:

 function foo(){} 

Un simulacro es una función artificial que se utiliza para evitar las dependencias de SO, entorno o hardware durante las pruebas:

 function foo(bar){ window = this; return window.toString(bar); } 

En términos de aserciones y estado:

  • Los simulacros se afirman antes de un evento o cambio de estado
  • Los stubs no se afirman, proporcionan estado antes de un evento para evitar la ejecución de código de unidades no relacionadas
  • Los espías se configuran como talones, luego se afirman después de un evento o cambio de estado
  • Las falsificaciones no se afirman, se ejecutan después de un evento con dependencias codificadas para evitar el estado

Referencias

  • Geek Glossary: ​​Simulacro
  • Geek Glossary: ​​Stub
  • Geek Glossary: ​​Espía
  • Dobles de prueba: falsificaciones, burlas y trozos

una gran cantidad de respuestas válidas allí, pero creo que vale la pena mencionar esta forma tío bob: https://8thlight.com/blog/uncle-bob/2014/05/14/TheLittleMocker.html

la mejor explicación con ejemplos!

Un Stub es un objeto que implementa una interfaz de un componente, pero en lugar de devolver lo que devolvería el componente cuando se le llama, el stub se puede configurar para devolver un valor que se adapte a la prueba. Usando stubs, una prueba unitaria puede probar si una unidad puede manejar varios valores de retorno de su colaborador. Usar un stub en lugar de un colaborador real en una prueba unitaria podría expressse así:

prueba unitaria -> stub

unidad de prueba -> unidad -> stub

prueba de unidad afirma sobre los resultados y el estado de la unidad

Primero, la prueba unitaria crea el stub y configura sus valores de retorno. Luego, la prueba unitaria crea la unidad y establece el stub sobre ella. Ahora la prueba unitaria llama a la unidad que a su vez llama al stub. Finalmente, la prueba unitaria hace afirmaciones sobre los resultados de las llamadas al método en la unidad.

Un simulacro es como un talón, solo que también tiene métodos que hacen posible determinar qué métodos se invocaron en el simulacro . Usando un simulacro es posible tanto probar si la unidad puede manejar varios valores de retorno correctamente, y también si la unidad usa el colaborador correctamente. Por ejemplo, no puede ver por el valor devuelto por un objeto dao si los datos se leyeron desde la base de datos usando un Statement o un PreparedStatement. Tampoco se puede ver si se llamó al método connection.close () antes de devolver el valor. Esto es posible con burlas. En otras palabras, los simulacros permiten probar la interacción completa de una unidad con un colaborador. No solo los métodos colaboradores que devuelven los valores utilizados por la unidad. Usar un simulacro en una prueba unitaria podría expressse así:

prueba unitaria -> simulacro

unidad de prueba -> unidad -> simulacro

prueba de unidad afirma sobre el resultado y el estado de la unidad

prueba de unidad afirma sobre los métodos llamados en simulacro

Más detalle >> Aquí

Stub y simulacro punto de vista de prueba:

  • Stub es una implementación ficticia realizada por el usuario de manera estática , es decir, en Stub escribiendo el código de implementación. Por lo tanto, no puede manejar la definición del servicio y la condición dinámica, normalmente esto se hace en el marco JUnit sin utilizar el marco de burla.

  • Mock también es una implementación ficticia, pero su implementación se realiza de forma dinámica mediante el uso de marcos de Mocking como Mockito. De modo que podemos manejar la definición de condición y servicio de una manera dinámica, es decir, se pueden crear simulaciones dinámicamente a partir del código en tiempo de ejecución. Entonces, usando simulacro podemos implementar Stubs dinámicamente.

Lo siguiente es mi entendimiento …

  • si crea objetos de prueba localmente y alimenta su servicio local con eso, está utilizando un objeto simulado. esto dará una prueba para el método que implementó en su servicio local. se usa para verificar comportamientos

  • cuando obtiene los datos de prueba del proveedor de servicios real, aunque desde una versión de prueba de la interfaz y obtiene una versión de prueba del objeto, está trabajando con stubs, el stub puede tener lógica para aceptar ciertas entradas y dar el resultado correspondiente para ayudarlo a realizar verificación de estado …

Los stubs se usan en métodos con un valor de retorno esperado que configura en su prueba. Los simulacros se usan en métodos nulos que se verifican en el Assert que se llaman.

Mock – Un simulacro intercepta una llamada a un método o función (o un grupo de métodos y funciones como en el caso de una clase simulada). No es una alternativa a ese método o función. En esa intercepción, el simulacro puede hacer lo que quiera, como registrar la entrada y salida, decidir cortocircuitar la llamada, cambiar el valor devuelto, etc.

Stub : un stub es una implementación de trabajo completa válida de un método o función (o grupo de métodos y funciones como en el caso de una clase stub) que tiene una interfaz / firma idéntica al método, función o grupo de métodos y funciones es stubbing para. Por lo general, la implementación restringida solo hace cosas que son aceptables dentro del contexto de una prueba unitaria, lo que significa que no hará IO, por ejemplo, mientras imita el comportamiento de la cosa que está cortando.

veamos Test Dobles:

  • Fake : las falsificaciones son objetos que tienen implementaciones que funcionan, pero que no son lo mismo que las de producción. Tales como : implementación en memoria del Objeto o Repositorio de Acceso a Datos.
  • Stub : Stub es un objeto que contiene datos predefinidos y lo usa para responder llamadas durante las pruebas. Tales como : un objeto que necesita tomar algunos datos de la base de datos para responder a una llamada a un método.

  • Mocks : Los mocks son objetos que registran las llamadas que reciben. En la afirmación de prueba, podemos verificar en Mocks que se realizaron todas las acciones esperadas. Tales como : una funcionalidad que llama al servicio de envío de correo electrónico. para más, simplemente mira esto .