testing - sismo - ¿Cuál es la diferencia entre un simulacro y un talón?
simulacro de incendio en escuelas (30)
He leído varios artículos sobre burla frente a aplastamiento en las pruebas, incluidas las simulaciones de Martin Fowler no son talones , pero aún no entiendo la diferencia
Prefacio
Hay varias definiciones de objetos, que no son reales. El término general es prueba doble . Este término abarca: ficticio , falso , talón , simulacro .
Referencia
Según el artículo de Martin Fowler :
- Los objetos ficticios se pasan pero nunca se usan. Por lo general, sólo se utilizan para rellenar las listas de parámetros.
- Los objetos falsos realmente tienen implementaciones de trabajo, pero usualmente toman algún atajo que los hace no adecuados para la producción (un buen ejemplo es una base de datos en memoria).
- 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.
Estilo
Mocks vs Stubs = Pruebas de comportamiento vs Pruebas estatales
Principio
De acuerdo con el principio de Prueba solo una cosa por prueba , puede haber varios talones en una prueba, pero generalmente solo hay una simulacro.
Ciclo vital
Ciclo de vida de prueba con apéndices:
- Configuración - Prepare el objeto que se está probando y sus colaboradores de stubs.
- Ejercicio - Probar la funcionalidad.
- Verificar estado: utilice afirmaciones para verificar el estado del objeto.
- Desmontaje - Limpieza de recursos.
Prueba de ciclo de vida con mocks:
- Datos de configuración: prepare el objeto que se está probando.
- Configuración de las expectativas : prepare las expectativas en simulacro que está siendo utilizado por el objeto primario.
- Ejercicio - Probar la funcionalidad.
- Verifique las expectativas : verifique que se hayan invocado los métodos correctos en simulacro.
- Verificar estado: utilice afirmaciones para verificar el estado del objeto.
- Desmontaje - Limpieza de recursos.
Resumen
Tanto las pruebas de simulacros como las de los apéndices responden a la pregunta: ¿Cuál es el resultado?
Las pruebas con simulacros también están interesadas en: ¿Cómo se ha logrado el resultado?
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 efecto en su prueba, entonces puede crear objetos ficticios con el propósito de crear nuevas instancias de una clase.
Fake : crea una implementación de prueba de una clase que puede depender de alguna infraestructura externa. (Es una buena práctica que su prueba de unidad NO interactúe con la infraestructura externa).
Ejemplo : crear una implementación falsa para acceder a una base de datos, reemplazarla con
in-memory
colecciónin-memory
.Stub : anule los métodos para devolver valores codificados de forma rígida, 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 auxiliar que devuelve valores codificados; tomando solo una pequeña fracción del tiempo.Simulacro : muy similar a
Stub
perointeraction-based
en lainteraction-based
lugar de estado. Esto significa que no espera queMock
devuelva algún valor, sino que asuma que se realiza un orden específico de llamadas de método.Ejemplo: Estás probando una clase de registro de usuario. Después de llamar a
Save
, debe llamar aSendConfirmationEmail
.
Stubs
y los Mocks
son en realidad subtipos de Mock
, ambos intercambian la implementación real con la implementación de prueba, pero por diferentes motivos específicos.
Creo que la diferencia más importante entre ellos es sus intenciones.
Déjame tratar de explicarlo en WHY stub vs. WHY Mock
Supongamos que estoy escribiendo un código de prueba para el controlador público de la línea de tiempo de mi cliente de 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 la API de twitter es muy lenta, lo que hace que mi prueba sea lenta. Sé que devolverá líneas de tiempo, por lo que hice un código auxiliar que simulaba la API HTTP de Twitter, de modo que mi prueba se ejecutará muy rápido y puedo ejecutar la prueba incluso si estoy desconectado.
- MOCK: Aún no he escrito ninguno de mis métodos de UI, y no estoy seguro de qué métodos necesito escribir para mi objeto ui. Espero saber cómo colaborará mi controlador con mi objeto ui escribiendo el código de prueba.
Al escribir simulado, descubre la relación de colaboración de los objetos al verificar que se cumplen las expectativas, mientras que el código auxiliar simula el comportamiento del objeto.
Le sugiero leer este artículo si está tratando de saber más sobre simulacros: http://jmock.org/oopsla2004.pdf
Creo que la respuesta más simple y clara sobre esta pregunta la da Roy Osherove en su libro The art of Unit Testing (página 85)
La forma más sencilla de saber que estamos tratando con un código auxiliar es notar que el código auxiliar nunca puede fallar en la prueba. Las afirmaciones de que los usos de prueba son siempre contra la clase bajo prueba.
Por otro lado, la prueba utilizará un objeto simulado para verificar si la prueba falló o no. [...]
Nuevamente, el objeto simulado es el objeto que utilizamos para ver si la prueba falló o no.
Eso significa que si estás haciendo afirmaciones en contra de lo falso, significa que estás usando lo falso como simulacro, si estás usando el falso solo para ejecutar la prueba sin aserción sobre eso, estás usando el falso como un talón.
Desde los simulacros de papel , no objetos , de 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 apéndices, pero también incluyen aserciones para instrumentar las interacciones del objeto objetivo con sus vecinos.
Entonces, las principales diferencias son:
- las expectativas establecidas en los talones son generalmente genéricas, mientras que las expectativas establecidas en simulacros pueden ser más "inteligentes" (p. ej., devolver esto en la primera llamada, esto en la segunda, etc.).
- los stubs se utilizan principalmente para configurar entradas indirectas del SUT , mientras que los simulacros se pueden usar para probar tanto las entradas indirectas como las salidas indirectas del SUT.
En resumen, al mismo tiempo que intentamos disipar la confusión del título del artículo de Fowler : los simulacros son talones, pero no solo son talones .
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 talón con una afirmación de que el método se llama.
Entonces, como Sean Copenhaver describió en su respuesta, la diferencia es que los simulacros establecen expectativas (es decir, hacen afirmaciones, acerca de si o cómo se llaman).
Hay muchas respuestas válidas ahí arriba, pero creo que vale la pena mencionar este formulario tío Bob: https://8thlight.com/blog/uncle-bob/2014/05/14/TheLittleMocker.html
La mejor explicación con ejemplos!
He usado ejemplos de python en mi respuesta para ilustrar las diferencias.
Stub - Stubbing es una técnica de desarrollo de software que se utiliza para implementar métodos de clases al inicio del ciclo de vida del desarrollo. Se utilizan comúnmente como marcadores de posición para la implementación de una interfaz conocida, donde la interfaz se finaliza o se conoce pero la implementación aún no se conoce o finaliza. Comienza con los apéndices, lo que simplemente significa que solo escribes la definición de una función y dejas el código real 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 apéndice devuelva una respuesta estática para que otras partes de su código puedan usar la respuesta de inmediato. Los objetos de código auxiliar proporcionan una respuesta válida, pero es estática, independientemente de la entrada que pase, 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 los casos de prueba simulados, que validan que ciertos métodos se llaman en esos objetos. Los objetos simulados son objetos simulados que imitan el comportamiento de objetos reales de forma controlada. Por lo general, crea un objeto simulado para probar el comportamiento de algún otro objeto. Las simulaciones nos permiten simular recursos que no están disponibles o son demasiado difíciles de manejar para la prueba de unidades.
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 se llamó. Puede usar simulacro con objetos, no solo las funciones como se muestra aquí, y también puede devolver un valor para que un objeto simulado se pueda usar para reemplazar un talón para la prueba.
Más información sobre unittest.mock , la nota en Python 2.x mock no se incluye en unittest, pero es un módulo descargable que se puede descargar a través de pip (simulación pip install).
También he leído "El arte de las pruebas unitarias" de Roy Osherove y creo que sería genial si se escribiera un libro similar utilizando ejemplos de Python y Python. Si alguien sabe de tal libro, por favor comparta. Saludos :)
Leyendo todas las explicaciones anteriores, déjame intentar condensar:
- Stub : una pieza de código ficticia que permite la ejecución de la prueba, pero no le importa lo que le pase.
- 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 las llamadas sin reemplazar el objeto original completo.
Los apéndices se utilizan en métodos con un valor de retorno esperado que configura en su prueba. Los simulacros se utilizan en métodos nulos que se verifican en el mensaje de verificación de que se llaman.
Los talones no fallan en tus pruebas, puede burlarse.
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 los principiantes. El artículo de Martin Fowlers es una lectura dura especialmente para principiantes como yo.
Me gusta la explicación de Roy Osherove [enlace de video] .
Cada clase u objeto creado es falso. Es un simulacro si verificas las llamadas en contra. De lo contrario es un trozo.
Para ser muy claro y práctico:
Stub: una clase u objeto que implementa los métodos de la clase / objeto 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'';
}
}
Simulacro: Lo mismo que el código auxiliar, pero agrega cierta lógica que "verifica" cuando se llama a un método, por lo que puede estar seguro de que alguna implementación está llamando a ese método.
Como @mLevan dice, imagine como ejemplo que está probando una clase de registro de usuario. Después de llamar a Guardar, debe llamar a SendConfirmationEmail.
Un código muy estúpido Ejemplo:
var Mock = {
calls: {
method_a: 0
}
method_a: function(param_a, param_b){
this.method_a++;
console.log(''Mock.method_a its been called!'');
}
}
Punto de vista de pruebas de stub y mock:
Stub es una implementación ficticia realizada por el usuario de forma estática , es decir, en Stub que escribe 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 de JUnit sin utilizar el marco de simulacro.
Mock también es una implementación ficticia, pero su implementación se realiza de forma dinámica mediante el uso de marcos de simulacros como Mockito. Así que podemos manejar la definición de condiciones y servicios de forma dinámica, es decir, los simulacros se pueden crear dinámicamente desde el código en tiempo de ejecución. Entonces usando simulacros podemos implementar Stubs dinámicamente.
Si lo comparas con la depuración:
Stub es como asegurarse de que un método devuelva el valor correcto
Simulacro es como entrar en el método y asegurarse de que todo está correcto antes de devolver el valor correcto.
Stub es simple objeto falso. Simplemente se asegura de que la prueba se realice sin problemas.
La burla es un talón más inteligente. Usted verifica que su prueba pasa a través de él.
Un falso es un término genérico que se puede usar para describir un código auxiliar o un objeto simulado (escrito a mano o de otra manera), porque ambos se parecen al objeto real.
Si un falso es un talón o un simulacro depende de cómo se usa en la prueba actual. Si se usa para verificar una interacción (afirmada en contra), es un objeto simulado. De lo contrario, es un talón.
Las falsificaciones se aseguran de que la prueba se realice sin problemas. Significa que el lector de su futura prueba comprenderá cuál será el comportamiento del objeto falso, sin necesidad de leer su código fuente (sin tener que depender de un recurso externo).
¿Qué significa ejecutar 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("[email protected]", "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 servicio falso error falso para simular ese resultado, entonces su código de prueba podrá probar MailService.SendEMail () método. Como ve, necesita simular un resultado que sea de otra clase de Servicio de Error de Dependencia Externa.
Un código auxiliar es una función vacía que se utiliza para evitar excepciones no controladas durante las pruebas:
function foo(){}
Un simulacro es una función artificial que se utiliza para evitar las dependencias del sistema operativo, el entorno o el hardware durante las pruebas:
function foo(bar){ window = this; return window.toString(bar); }
En términos de afirmaciones y estados:
- Se simulan las simulaciones antes de un evento o cambio de estado
- Los apéndices no se activan, proporcionan un 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
- Los falsos no se confirman, se ejecutan después de un evento con dependencias codificadas para evitar el estado
Referencias
Un simulacro es solo probar el comportamiento, asegurándose de que ciertos métodos sean llamados. Un Stub es una versión comprobable (per se) de un objeto en particular.
¿Qué quieres decir con una forma de Apple?
Un talón es un objeto falso construido para propósitos de prueba. Un simulacro es un talón que registra si las llamadas esperadas ocurrieron efectivamente.
Vea a continuación el ejemplo de simulacros vs stubs usando C # y el framework Moq. 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
{
/// <summary>
/// Test using Mock to Verify that GetNameWithPrefix method calls Repository GetName method "once" when Id is greater than Zero
/// </summary>
[TestMethod]
public void GetNameWithPrefix_IdIsTwelve_GetNameCalledOnce()
{
// Arrange
var mockEntityRepository = new Mock<IEntityRepository>();
mockEntityRepository.Setup(m => m.GetName(It.IsAny<int>()));
var entity = new EntityClass(mockEntityRepository.Object);
// Act
var name = entity.GetNameWithPrefix(12);
// Assert
mockEntityRepository.Verify(m => m.GetName(It.IsAny<int>()), Times.Once);
}
/// <summary>
/// Test using Mock to Verify that GetNameWithPrefix method doesn''t call Repository GetName method when Id is Zero
/// </summary>
[TestMethod]
public void GetNameWithPrefix_IdIsZero_GetNameNeverCalled()
{
// Arrange
var mockEntityRepository = new Mock<IEntityRepository>();
mockEntityRepository.Setup(m => m.GetName(It.IsAny<int>()));
var entity = new EntityClass(mockEntityRepository.Object);
// Act
var name = entity.GetNameWithPrefix(0);
// Assert
mockEntityRepository.Verify(m => m.GetName(It.IsAny<int>()), Times.Never);
}
/// <summary>
/// Test using Stub to Verify that GetNameWithPrefix method returns Name with a Prefix
/// </summary>
[TestMethod]
public void GetNameWithPrefix_IdIsTwelve_ReturnsNameWithPrefix()
{
// Arrange
var stubEntityRepository = new Mock<IEntityRepository>();
stubEntityRepository.Setup(m => m.GetName(It.IsAny<int>()))
.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";
}
}
}
siguiente es mi entendimiento ...
Si crea objetos de prueba localmente y alimenta su servicio local con eso, está utilizando un objeto simulado. Esto le dará una prueba del método que implementó en su servicio local. Se utiliza para verificar comportamientos.
cuando obtiene los datos de prueba del proveedor de servicios real, aunque de una versión de prueba de la interfaz y obtiene una versión de prueba del objeto, está trabajando con apéndices, el apéndice puede tener lógica para aceptar cierta entrada y dar la salida correspondiente para ayudarlo a realizar verificación del estado ...
vamos a ver las pruebas de dobles:
- Falso : Los falsos son objetos que tienen implementaciones en funcionamiento, pero no son lo mismo que uno de producción. Tales como : implementación en memoria del objeto de acceso a datos o repositorio.
Stub : Stub es un objeto que contiene datos predefinidos y lo utiliza 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 de método.
Simulacros : los simulacros 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 solo verifica esto
Simulacro : 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 la salida, decidir cortocircuitar la llamada, cambiar el valor devuelto, etc.
Stub : un stub es una implementación válida y completa 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 aplastar para La implementación de apéndices generalmente solo hará cosas que son aceptables dentro del contexto de una prueba unitaria, eso significa que no hará IO por ejemplo, mientras imita el comportamiento de la cosa que apunta.
Stub nos ayuda a ejecutar la prueba. ¿Cómo? Da valores que ayudan a ejecutar la prueba. Estos valores en sí 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 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 aseverar.
Talón
Creo que la mayor distinción es que un código que ya ha escrito con un comportamiento predeterminado. Por lo tanto, tendría una clase que implementa la dependencia (clase abstracta o interfaz más probable) que está falsificando para propósitos de prueba y los métodos simplemente serían eliminados con respuestas establecidas. Ellos no harían nada sofisticado y ya habrías escrito el código de talón fuera de tu prueba.
Burlarse de
Un simulacro es algo que, como parte de su prueba, debe configurar con sus expectativas. Un simulacro no se configura de manera predeterminada, por lo que tiene un código que lo hace en su prueba. Las simulaciones de una manera se determinan en el tiempo de ejecución, ya que el código que establece las expectativas debe ejecutarse antes de hacer algo.
Diferencia
Las pruebas escritas con simulacros generalmente siguen una initialize -> set expectations -> exercise -> verify
patrón de prueba. Mientras que el código auxiliar escrito previamente debería seguir una initialize -> exercise -> verify
.
Semejanza
El propósito de ambos es eliminar las pruebas de todas las dependencias de una clase o función para que sus pruebas estén más enfocadas y sean más simples en lo que intentan probar.
Un código auxiliar es un objeto que implementa una interfaz de un componente, pero en lugar de devolver lo que el componente devolvería cuando se llamara, el código auxiliar puede configurarse para devolver un valor que se adapte a la prueba. Al usar stubs, una prueba de unidad puede probar si una unidad puede manejar varios valores de retorno de su colaborador. El uso de un código auxiliar en lugar de un colaborador real en una prueba unitaria se podría expresar así:
prueba unitaria -> trozo
prueba de unidad -> unidad -> trozo
prueba de unidad afirma sobre los resultados y el estado de la unidad
Primero, la prueba unitaria crea el código auxiliar y configura sus valores de retorno. Luego, la prueba de la unidad crea la unidad y establece el talón en ella. Ahora la prueba de la unidad llama a la unidad que, a su vez, llama al código auxiliar. Finalmente, la prueba de la unidad hace afirmaciones sobre los resultados de las llamadas del 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 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 desde un objeto dao si los datos se leyeron de la base de datos utilizando una declaración o una declaración preparada. Tampoco puede ver si se llamó al método connection.close () antes de devolver el valor. Esto es posible con las burlas. En otras palabras, los simulacros permiten probar una interacción completa de las unidades con un colaborador. No solo los métodos de colaboración que devuelven los valores utilizados por la unidad. El uso de un simulacro en una prueba unitaria podría expresarse así:
prueba de unidad -> simulacro
prueba de unidad -> unidad -> simulacro
prueba de unidad afirma sobre el resultado y el estado de la unidad
prueba de unidad afirma en los métodos llamados en simulacro
Más detalle >> Here
- Stubs vs. Mocks
- Talones
- Proporcionar respuestas específicas a los métodos de llamadas.
- por ejemplo: myStubbedService.getValues () simplemente devuelve una cadena que necesita el código bajo prueba
- Utilizado por el código bajo prueba para aislarlo.
- no puede fallar la prueba
- por ejemplo: myStubbedService.getValues () solo devuelve el valor de apéndice
- A menudo implementamos métodos abstractos.
- Proporcionar respuestas específicas a los métodos de llamadas.
- Burlas
- "superconjunto" de talones; Puede afirmar que ciertos métodos son llamados
- ej .: verifique que myMockedService.getValues () se llame solo una vez
- utilizado para probar el comportamiento del código bajo prueba
- puede fallar la prueba
- ej .: verifique que se haya llamado una vez a myMockedService.getValues (); la verificación falla, porque mi código probado no llamó a myMockedService.getValues ()
- a menudo se burla de las interfaces
- "superconjunto" de talones; Puede afirmar que ciertos métodos son llamados
- Talones