¿Cuál es la diferencia entre un simulacro y un trozo?

963

He leído varios artículos sobre burlarse y tropezar en las pruebas, incluidos Los simulacros de Martin Fowler no son trozos , pero aún no entiendo la diferencia.

never_had_a_name
fuente
75
@OP Porque no hay diferencia. Este artículo, tanto como amado por la comunidad, es, con el debido respeto, haciendo que todo sea innecesario y confuso al agregar un significado adicional a las palabras que son fáciles de entender de otra manera y al complicar las cosas innecesariamente. Mock es solo un simulacro, algo que ejecuta una lógica comercial falsa en lugar de una real. Verificar el comportamiento al final es tu elección, pero sigue siendo una burla. O como quieras llamarlo, pero hazlo UNO. No dividir un pelo. Hazlo simple, para que la gente pueda entender tu concepto fácilmente, con lo cual el artículo anterior falla.
wst
10
"La clasificación entre simulacros, falsificaciones y trozos es muy inconsistente en toda la literatura". Con muchas citas. Todavía una de mis citas favoritas de Wikipedia, si es que existe :) en.wikipedia.org/wiki/Mock_object
JD.
11
que el artículo de Martin Fowler es realmente difícil de entender para principiantes.
lmiguelvargasf
1
Según tengo entendido, un trozo sería un objeto desechable para su prueba, como una recopilación de datos ficticios. Un simulacro sería una versión ingeniosamente anulada de algo más complejo, como una capa de servicio con varios métodos, para los que podría haber cambiado el comportamiento de sus pruebas. Las dos cosas se usan juntas, como si pudieras pasar algunos objetos tropezados en tu capa simulada.
JsonStatham

Respuestas:

746

Talón

Creo que la mayor distinción es que un trozo que ya has 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 fines de prueba y los métodos simplemente se eliminarían con las respuestas establecidas. No harían nada lujoso y ya habría escrito el código tropezado 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. En cierto modo, los simulacros se determinan en tiempo de ejecución ya que el código que establece las expectativas debe ejecutarse antes de que hagan algo.

Diferencia entre simulacros y trozos

Las pruebas escritas con simulacros generalmente siguen un initialize -> set expectations -> exercise -> verifypatrón de prueba. Mientras que el trozo preescrito seguiría uninitialize -> exercise -> verify .

Similitud entre simulacros y trozos

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 enfocadas y más simples en lo que están tratando de probar.

Sean Copenhaver
fuente
876

Prefacio

Hay varias definiciones de objetos que no son reales. El término general es prueba doble . Este término abarca: ficticio , falso , trozo , simulacro .

Referencia

Según el artículo de Martin Fowler :

  • Los objetos ficticios se pasan pero nunca se usan realmente. Por lo general, solo se usan para completar listas de parámetros.
  • Falso objetos realidad tienen implementaciones que funcionan, pero generalmente toman algún atajo que los hace no adecuados para la producción (una base de datos en memoria es un buen ejemplo).
  • Trozos 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.

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 trozos en una prueba, pero generalmente solo hay un simulacro.

Ciclo vital

Pruebe el ciclo de vida con trozos:

  1. Configuración: prepare el objeto que se está probando y sus stubs colaboradores.
  2. Ejercicio: prueba la funcionalidad.
  3. Verificar estado: use afirmaciones para verificar el estado del objeto.
  4. Desmontaje - Limpiar recursos.

Pruebe el ciclo de vida con simulacros:

  1. Datos de configuración: prepare el objeto que se está probando.
  2. Configurar expectativas : prepare las expectativas en simulacro que está utilizando el objeto primario.
  3. Ejercicio: prueba la funcionalidad.
  4. Verifique las expectativas : verifique que los métodos correctos se hayan invocado simulacros.
  5. Verificar estado: use afirmaciones para verificar el estado del objeto.
  6. Desmontaje - Limpiar recursos.

Resumen

Tanto las pruebas simuladas como las de prueba dan una respuesta 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?

Ryszard Dżegan
fuente
Espera, ¿los simulacros también devuelven respuestas enlatadas? Porque de lo contrario, ¿por qué responden la pregunta?
AturSams
Por lo que escribió, puedo decir que simulacros = apéndices + expectativas y verificaciones, porque los simulacros "brindan 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" (igual que los apéndices). ¡Y el ejemplo que Fowler mostró como ejemplo de un trozo es en realidad un ejemplo de un espía! Eso significa que un simulacro es un trozo, y un espía es un trozo. Y un trozo es solo un objeto que tiene varios métodos de trabajo. Eso también explica por qué Mockito desaprobó el método stub ().
kolobok
Lo que me parece confuso acerca de esto y la respuesta aceptada es esta "configuración de expectativas", ¿qué significa? Por lo general, en el "código principal" crea los resultados que esperaría. Sin embargo, parece que pones las expectativas de alguna manera EN el objeto simulado, lo que no tiene sentido para mí. TAMBIÉN, podría ejercer fácilmente el simulacro con algo de información, almacenar el resultado, crear "las expectativas" más tarde y luego comparar. Usas terminología que me parece demasiado abstracta y ambigua.
IceFire
365

Un trozo es un simple objeto falso. Solo se asegura de que la prueba funcione sin problemas.
Un simulacro es un trozo más inteligente. Verifica que su prueba lo pasa.

Arnis Lapsa
fuente
33
Creo que esta es la respuesta más sucinta y precisa. Para llevar: un falso trozo de IS-A. stackoverflow.com/a/17810004/2288628 es la versión más larga de esta respuesta.
PoweredByRice
8
No creo que un simulacro sea un trozo. Los simulacros se usan para afirmar y nunca deben devolver datos, los apéndices se usan para devolver datos y nunca deben afirmarse.
dave1010
2
@ dave1010 Los simulacros definitivamente pueden devolver datos o incluso lanzar una excepción. Deberían hacerlo en respuesta a los parámetros que les fueron transmitidos.
Trenton
2
@trenton si un objeto regresa o se lanza según los datos pasados, entonces es falso , no un simulacro. Los talones prueban cómo su SUT maneja la recepción de mensajes, los simulacros prueban cómo su SUT envía mensajes. Mezclar los 2 es probable que conduzca a un mal diseño de OO.
dave1010
8
Creo que esto es genial: un trozo devuelve respuestas a las preguntas. ¡Un simulacro también devuelve respuestas a las preguntas (es un trozo) pero también verifica que la pregunta se haya hecho!
Leif
238

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

  • Dummy : solo valores falsos para satisfacer el 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, 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 depender de alguna infraestructura externa. (Es una buena práctica que la prueba de la unidad NO interactúe realmente con la infraestructura externa).

    Ejemplo : crear una implementación falsa para acceder a una base de datos, reemplazarla con una in-memorycolección.

  • Stub : métodos de anulación para devolver valores codificados, también conocidos como state-based.

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

  • Simulacro : muy similar Stubpero interaction-basedno basado en el estado. Esto significa que no espera Mockdevolver algún valor, sino asumir que se realiza un orden específico de llamadas a métodos.

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

Stubsy en Mocksrealidad son subtipos de Mock, ambos intercambian implementación real con implementación de prueba, pero por diferentes razones específicas.

Lev
fuente
175

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 trozo con una afirmación de que se llama al método.

Entonces, como Sean Copenhaver describió en su respuesta, la diferencia es que se burla de las expectativas establecidas (es decir, hace afirmaciones sobre si se les llama o cómo se llaman).

Dillon Kearns
fuente
Para complementar la publicación de Dillon, piense en esto, tiene una Clase llamada "MakeACake" que toma varias bibliotecas: Leche, Huevos, Azúcar, Horno.
aarkerio
139

Los trozos no fallan en las pruebas, simulacro puede.

mk_
fuente
2
Y creo que esto es bueno, ya sabes si las pruebas tienen el mismo comportamiento después de la refactorización.
RodriKing
1
@RodriKing Tengo el mismo sentimiento. Al igual que con Mock, con cualquier cambio en el código de producción, tiene los cambios correspondientes al código de prueba. Que es dolor! Con Stubs, parece que sigue probando el comportamiento, por lo que no es necesario realizar micro cambios con el código de prueba.
tucq88
35

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

La forma más fácil de saber que estamos lidiando con un trozo es notar que el trozo nunca puede fallar la prueba. Las afirmaciones que usa la prueba siempre están en contra de 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 usamos para ver si la prueba falló o no.

Eso significa que si está haciendo afirmaciones contra el falso, significa que está usando el falso como un simulacro, si está usando el falso solo para ejecutar la prueba sin afirmación, está usando el falso como un trozo.

Ghini Antonio
fuente
2
Me gustaría que tu respuesta llegara a la cima. Aquí está R. Osherove explicando esto youtu.be/fAb_OnooCsQ?t=1006 .
Michael Ekoka
31

Leyendo todas las explicaciones anteriores, déjame intentar condensar:

  • Stub : un código ficticio que permite que se ejecute la prueba, pero no le importa lo que le pase.
  • Simulacro : un fragmento de código ficticio 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 todo el objeto original.
O'Rooney
fuente
44
Buena respuesta. Sin embargo, Mock suena bastante similar a Spy, según tu definición. Sería bueno si actualizara su respuesta para incluir algunos dobles de prueba más.
Rowan Gontier
No había oído hablar de Spy cuando escribí esta respuesta.
O'Rooney
23

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

¿Qué quieres decir con Apple?

NebulaFox
fuente
19
"¿Qué quieres decir con Apple?" Use Helvetica
kubi
77
En forma de Apple en lugar de en forma de Microsoft :)
never_had_a_name
2
¿Ayuda esto a la situación?
NebulaFox
21

Si lo compara con la depuración:

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

Mock es como entrar en el método y asegurarse de que todo lo que hay dentro sea correcto antes de devolver el valor correcto.

Gilmore feliz
fuente
20

El uso de un modelo mental realmente me ayudó a comprender esto, en lugar de todas las explicaciones y artículos, que no se "hundieron".

Imagina que tu hijo tiene una placa de vidrio sobre la mesa y comienza a jugar con ella. Ahora, tienes miedo de que se rompa. Entonces, le das un plato de plástico en su lugar. Eso sería un simulacro (mismo comportamiento, misma interfaz, implementación "más suave").

Ahora, digamos que no tiene el reemplazo de plástico, entonces explique "¡Si continúa jugando con él, se romperá!". Eso es un trozo , proporcionó un estado predefinido de antemano.

Un Dummy sería el tenedor que ni siquiera usó ... y un Spy podría ser algo así como proporcionar la misma explicación que ya usó que funcionó.

Moshisho
fuente
19

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

Voy a tratar de explicarlo en QUÉ talón vs QUÉ simulacro

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

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á las líneas de tiempo, así que hice un código auxiliar que simula la API HTTP de Twitter, para que mi prueba se ejecute muy rápido, y puedo ejecutar la prueba incluso cuando estoy desconectado.
  • MOCK: Todavía no he escrito ninguno de mis métodos de IU, y no estoy seguro de qué métodos necesito escribir para mi objeto ui. Espero saber cómo mi controlador colaborará con mi objeto ui escribiendo el código de prueba.

Al escribir simulacro, descubre la relación de colaboración de los objetos verificando que se cumplan las expectativas, mientras que el código auxiliar solo simula el comportamiento del objeto.

Sugiero leer este artículo si estás tratando de saber más sobre simulacros: http://jmock.org/oopsla2004.pdf

Joe Yang
fuente
1
Creo que tienes la idea correcta, pero Dillon Kearns lo explicó mucho más claramente.
O'Rooney
19

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';
   }
}

Mock: lo mismo de stub, pero agrega algo de 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 dice @mLevan, 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!');
   }
}
R01010010
fuente
16

Esta diapositiva explica muy bien las principales diferencias.

ingrese la descripción de la imagen aquí

* De CSE 403 Lecture 16, Universidad de Washington (diapositiva creada por "Marty Stepp")

Aviram Fireberger
fuente
Esta es la explicación más clara de la diferencia entre los dos, IMO. Para el trozo: el probador toma el trozo y lo usa directamente dentro de la clase bajo prueba. Pero para Mock, el probador tiene que determinar cómo se usará el objeto Mock. En diferentes casos, se comportará de manera diferente. Por el contrario, no se espera que el código auxiliar se comporte de manera diferente, pero se usa como está (lo que significa devolver los mismos datos cada vez que se contacta)
Dexter
12

Me gusta la explicación de Roy Osherove [enlace de video] .

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

nitishagar
fuente
12
  • Trozos contra simulacros
    • Trozos
      1. proporcionar respuestas específicas a llamadas a métodos
        • Por ejemplo: myStubbedService.getValues ​​() solo devuelve una Cadena que necesita el código bajo prueba
      2. utilizado por el código bajo prueba para aislarlo
      3. no puede fallar la prueba
        • Por ejemplo: myStubbedService.getValues ​​() solo devuelve el valor stubbed
      4. a menudo implementan métodos abstractos
    • Simulacros
      1. "superconjunto" de trozos; puede afirmar que ciertos métodos se llaman
        • ej .: verifique que myMockedService.getValues ​​() se llame solo una vez
      2. usado para probar el comportamiento del código bajo prueba
      3. puede fallar la prueba
        • ej .: verifique que myMockedService.getValues ​​() haya sido llamado una vez; la verificación falla, porque mi código probado no llamó a myMockedService.getValues ​​()
      4. a menudo se burla de las interfaces
Relu Mesaros
fuente
11

veamos Test Dobles:

  • Falso : Los falsos son objetos que tienen implementaciones que funcionan, pero no son lo mismo que uno de producción. Tales como : implementación en memoria de Data Access Object o Repository.
  • Stub : Stub es un objeto que contiene datos predefinidos y los 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 al método.

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

Alireza Rahmani Khalili
fuente
1
mejor respuesta en mi opinión
Ero Stefano
9

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), porque ambos se parecen al objeto real.

Si un falso es un trozo o un simulacro depende de cómo se use en la prueba actual. Si se usa para verificar una interacción (afirmada 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 que la prueba funcione 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 hacerlo necesita simular una excepción en su método de prueba, por lo que solo necesita crear una clase Fake Stub errorService para simular ese resultado, luego su código de prueba podrá probar Método mailService.SendEMail (). Como puede ver, necesita simular un resultado que provenga de otra clase External Dependency ErrorService.

Mustafa Ekici
fuente
8

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 fijos. Los objetos simulados actúan como trozos, pero también incluyen aserciones para instrumentar las interacciones del objeto de destino con sus vecinos.

Entonces, las principales diferencias son:

  • Las expectativas establecidas en los apéndices son generalmente 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 salidas indirectas del SUT.

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

Dimos
fuente
1
Creo que tienes razón, pero es por eso que el artículo de Fowler es confuso, el título del artículo es "Los simulacros no son trozos" ... ¡¿pero lo son ?! ¯_ (ツ) _ / ¯
stonedauwg
@stonedauwg, de hecho, edité mi publicación para incorporar su juego de palabras y una aclaración. Espero que esto ayude un poco más.
Dimos
@stonedauwg, un simulacro no es un trozo, al igual que un rectángulo no es un cuadrado. :)
seanriordan08
7

Estaba leyendo El arte de las pruebas unitarias , y me topé con la siguiente definición:

Un falso es un término genérico que se puede usar para describir un trozo o un objeto simulado (escrito a mano o de otro modo), porque ambos se parecen al objeto real. Si un falso es un trozo o un simulacro depende de cómo se use en la prueba actual. si se usa para verificar una interacción (afirmada contra), es un objeto simulado . De lo contrario, es un trozo .

Afonso Matos
fuente
5

Encontré 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.

AI
fuente
4

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

Harry
fuente
"Entonces, en lugar de interactuar directamente con la base de datos, interactuamos con Hashmap". ... porque todavía no tenía tiempo para codificar el Módulo de base de datos, y no pudimos ejecutar el código de prueba sin usar el código auxiliar. De lo contrario, el mismo Hasmap sería una burla. ¿Correcto?
Boris Däppen
4

Vea a continuación el ejemplo de simulacros vs stubs usando C # y el marco Moq. Moq no tiene una palabra clave especial para Stub, pero también puede usar el objeto Mock para crear stub.

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";
        }
    }
}
Adarsh ​​Shah
fuente
4

Punto de vista de prueba Stub y Mock:

  • Stub es una implementación ficticia realizada por el usuario de forma 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 usar el marco burlón.

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

Premraj
fuente
3

Además de respuestas útiles, una de las más puntos poderosos de usar simulacros que Subs

Si el colaborador [del cual depende el código principal] no está bajo nuestro control (p. Ej., De una biblioteca de terceros),
en este caso, el código auxiliar es más difícil de escribir que simular .

ahmednabil88
fuente
2

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 se finaliza o se conoce pero la implementación aún no se conoce o finaliza. Comienzas con stubs, 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 código. También puede hacer que su código auxiliar 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 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"

Burlarse de objetos simulados se usan en casos de prueba simulados que validan que ciertos métodos se invocan en esos objetos. Los objetos simulados son objetos simulados que imitan el comportamiento de los objetos reales de manera 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 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 solo ejecuta rm y afirma el parámetro con el que fue llamado. Puede usar simulacros con objetos no solo funciones como se muestra aquí, y también puede devolver un valor para que se pueda usar un objeto simulado para reemplazar un trozo para la prueba.

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

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. Salud :)

radtek
fuente
2

Un trozo es un objeto falso creado con fines de prueba. Un simulacro es un trozo que registra si las llamadas esperadas ocurrieron efectivamente.

simon.denel
fuente
2

Un trozo 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 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 estado:

  • Se imponen simulacros antes de un evento o cambio de estado
  • Los apéndices no se afirman, proporcionan estado antes de un evento para evitar ejecutar código desde unidades no relacionadas
  • Los espías se configuran como trozos, 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

Paul Sweatte
fuente
2
+1 para agregar espías al glosario. Además, creo que te refieres a "Los espías están configurados como simulacros" no "Los espías están configurados como trozos"
Sameh Deabes
2

Un simulacro es tanto un objeto técnico como funcional .

El simulacro es técnico . De hecho, es creado por una biblioteca de imitación (EasyMock, JMockit y más recientemente Mockito son conocidos por estos) gracias a la generación de código de bytes .
La implementación simulada se genera de una manera en la que podríamos instrumentarla para devolver un valor específico cuando se invoca un método, pero también algunas otras cosas, como verificar que se invocó un método simulado con algunos parámetros específicos (verificación estricta) o cualesquiera que sean los parámetros ( sin control estricto).

Instanciar un simulacro:

@Mock Foo fooMock

Grabar un comportamiento:

when(fooMock.hello()).thenReturn("hello you!");

Verificación de una invocación:

verify(fooMock).hello()

Claramente, esta no es la forma natural de instanciar / anular la clase / comportamiento de Foo. Por eso me refiero a un aspecto técnico.

Pero el simulacro también es funcional porque es una instancia de la clase que necesitamos aislar del SUT. Y con comportamientos grabados en él, podríamos usarlo en el SUT de la misma manera que lo haríamos con un trozo.


El código auxiliar es solo un objeto funcional : es una instancia de la clase que necesitamos aislar del SUT y eso es todo. Eso significa que tanto la clase de código auxiliar como todos los accesorios de comportamiento necesarios durante nuestras pruebas unitarias deben definirse explícitamente.
Por ejemplo, para stub hello()necesitaría subclasificar la Fooclase (o implementar su interfaz que tiene) y anular hello() :

public class HelloStub extends Hello{    
  public String hello { 
      return "hello you!"; 
  }
}

Si otro escenario de prueba requiere otro retorno de valor, probablemente tendremos que definir una forma genérica para establecer el retorno:

public class HelloStub extends Hello{    
  public HelloStub(String helloReturn){
       this.helloReturn = helloReturn;
  }
  public String hello { 
      return helloReturn; 
  }
}

Otro escenario: si tuviera un método de efectos secundarios (sin retorno) y verificara que ese método fue invocado, probablemente debería haber agregado un booleano o un contador en la clase stub para contar cuántas veces se invocó el método.


Conclusión

El código auxiliar a menudo requiere mucha sobrecarga / código para escribir para su prueba unitaria. Qué simulación evita gracias a que proporciona funciones de grabación / verificación listas para usar.
Es por eso que hoy en día, el enfoque stub rara vez se usa en la práctica con el advenimiento de excelentes bibliotecas simuladas.


Sobre el artículo de Martin Fowler: No creo que sea un programador "simulador" mientras uso simulacros y evito trozos.
Pero uso simulacro cuando realmente es necesario (dependencias molestas) y estoy a favor de las pruebas de corte y mini-integración de prueba cuando pruebo una clase con dependencias cuya burla sería una sobrecarga.

davidxxx
fuente