¿Cómo se usan comúnmente los objetos simulados?

15

Hace poco leí un artículo que decía que los objetos simulados a menudo son mal entendidos y mal utilizados. ¿Hay algún antipatrón burlón claro que pueda tener en cuenta?

Armand
fuente
es el artículo que lees este? martinfowler.com/articles/mocksArentStubs.html
keppla
no ... no recuerdo la fuente exacta pero publicaré aquí si lo hago
Armand
Fui llevado a la tarea en stackoverflow por burlarse de la API mongodb. Me señalaron una publicación de blog que decía que está mal burlarse de cualquier clase que usted mismo no escribió. De hecho, no estoy de acuerdo con esto, pero la opinión está ahí afuera.
Kevin

Respuestas:

13

Odio ver burlas de clases concretas simples. Por ejemplo, tome la siguiente clase simple que no depende de nada más:

public class Person
{
    private readonly string _firstName;
    private readonly string _surname;

    public Person(string firstName, string surname)
    {
        if (String.IsNullOrEmpty(firstName))
        {
            throw new ArgumentException("Must have first name");
        }

        if (String.IsNullOrEmpty(surname))
        {
            throw new ArgumentException("Must have a surname");
        }

        _firstName = firstName;
        _surname = surname;
    }

    public string Name 
    {
        get
        {
            return _firstName + " " + _surname;
        }
    }
}

En cualquier prueba que involucre esta clase, preferiría que se creara una instancia real y se usara en lugar de que se extrajera alguna interfaz como 'IPerson', se usó una simulada y se establecieron expectativas. Al usar el real, su prueba es más realista (tiene las verificaciones de parámetros en su lugar y la implementación real de la propiedad 'Nombre'). Para una clase simple como esta, no está haciendo que sus pruebas sean más lentas, menos deterministas o enturbia la lógica (es probable que no necesite saber que se llamó a Nombre cuando se prueba alguna otra clase), que son las razones habituales para burlarse / tropezar

Como una extensión de esto, también he visto a personas escribir pruebas donde el simulacro se configura con una expectativa, luego el simulacro se llama directamente en la prueba. Como era de esperar, la prueba siempre pasará ... hmmmm ...

FinnNk
fuente
Afortunadamente, los frameworks burlones que he usado han podido burlarse de clases concretas, por lo que extraer interfaces en puntos inconvenientes no es un problema.
Armand
55
Eso no cambia el problema: este tipo de cosas simples generalmente no se deben burlar, incluso si está usando algo que relaja las limitaciones técnicas sobre lo que se puede burlar (por ejemplo, un marco simulado como TypeMock o un lenguaje dinámico).
FinnNk
Mi regla general siempre ha sido burlarse del comportamiento, no de los datos.
Ardave
10

Puede sonar obvio, pero: ¡No uses objetos simulados en el código de producción! He visto más de un ejemplo en el que el código de producción dependía de las características de ciertos objetos simulados ( MockHttpServletRequestdel Springframework, por ejemplo).

perdian
fuente
14
¿espero que hayas cumplido con tu deber sagrado y hayas enviado el código a DailyWTF?
keppla
1
En mi trabajo anterior, teníamos expresamente prohibido enviar cualquier cosa desde nuestra base de código a DWTF.
quant_dev
99
@quant_dev: El hecho de que tuvieran esa política implica cosas aterradoras sobre sus desarrolladores ...
John Fisher
1
Realmente no. Fue una startup que tuvo que desarrollar una base de código rápidamente para vender un producto, y luego comenzó a consolidarla y refactorizarla para pagar la deuda técnica, a medida que el producto maduró y el desarrollo inicial se vio obstaculizado por la (falta de) diseño inicial. Los gerentes sabían que la antigua base de código era una mierda e invertían tiempo y recursos en la refactorización, pero no querían arriesgarse a ninguna publicidad adversa.
quant_dev
Simplemente tomar atajos no es suficiente para que solo te den a diario ...
poolie
9

En mi opinión, es el método excesivo de verificación de invocación en simulacros. Siento que esta es una práctica impuesta por algunos marcos de simulación como EasyMock, donde el comportamiento simulado predeterminado es fallar siempre que haya una invocación de método adicional que no se especificó exactamente antes. Este tipo de comprobación estricta de métodos simulados puede conducir a diseños frágiles donde el más mínimo cambio en el código puede llevar a que falle un conjunto completo de pruebas, a pesar de que la funcionalidad principal sigue siendo la misma.

Una solución a esto es comenzar a usar trozos en lugar de simulacros. Un artículo que encontré particularmente esclarecedor sobre el tema fue uno que se encuentra en el Javadoc de Mockito: http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html (ver "2. ¿Qué tal un poco de tropezón?" ), enlace a: http://monkeyisland.pl/2008/07/12/should-i-worry-about-the-unexpected/ .

Me ha encantado trabajar con Mockito hasta ahora porque no impone este estricto comportamiento de burla, sino el uso de stubs. También impone el método de verificación de los específicos en lugar del objeto simulado completo; así que terminas comprobando solo los métodos que realmente importan en tu escenario de prueba.

Hay algunos libros aquí y allá que puedo recomendar que toquen este tema y burlas y en general:

xUnit Patrones

El arte de las pruebas unitarias: con ejemplos en .Net

Pruebas Java de próxima generación: TestNG y conceptos avanzados (este libro trata principalmente sobre testNG pero hay un buen capítulo sobre burlas)

Fabio Kenji
fuente
+1 para el punto sobre comprobaciones de invocación de método excesivas. Sin embargo, siempre existe la otra cara de la moneda en la que una invocación inesperada del método causa un error en su método. Afortunadamente, Mockito tiene la Answer.RETURNS_SMART_NULLSconfiguración de simulacros que ayuda a diagnosticar esto.
Bringer128
4

He observado pocos antipatrones en mi experiencia.

  • Las clases de dominio se burlan / se aprietan donde puede ocurrir un cambio de estado y eso debe verificarse.
  • Pruebas de integración que interactúan con una mezcla de simulacros y clases concretas que anula el propósito de las pruebas de integración.
  • Uso inadvertido de simulacros en el código de producción (Esto nunca debería suceder)

De lo contrario, mi experiencia con simulacros, especialmente Mockito, ha sido muy fácil. Han hecho pruebas muy fáciles de escribir y mantener. La prueba de interacción de vista / presentador de GWT es mucho más fácil con simulacros que el GWTTestCase.

Vinod R
fuente
2 y 3 son problemas definitivos! ¿Tienes un ejemplo simple de (1)?
Armand
2

Encuentro que las pruebas que utilizan simulacros en múltiples capas de una aplicación son particularmente difíciles de descifrar y cambiar. Sin embargo, creo que esto se ha mitigado en los últimos años gracias a las API de marco simulado mejoradas (uso JMock cuando es conveniente).

Hace 5 o 6 años, las API como EasyMock eran poderosas pero muy engorrosas. A menudo, el código de prueba que lo utilizaba era un orden de magnitud más complicado que el código que estaba probando. En aquel entonces traté de influir en los equipos en los que estaba para usarlo con moderación y conformarme con simples simulacros artesanales que eran simplemente implementaciones alternativas de interfaces específicamente para pruebas.

Recientemente, mis fuertes opiniones sobre esto se han vuelto más suaves a medida que las API burlonas han hecho que las pruebas que las utilizan sean más legibles. Esencialmente, quiero que otros desarrolladores puedan cambiar mi código (incluidas las pruebas) sin hacerlos sentir como si estuvieran analizando una serie de oscuras llamadas API.

rupjones
fuente