antipatrón : debe haber al menos dos elementos clave presentes para distinguir formalmente un antipatrón real de un simple mal hábito, mala práctica o mala idea:
- Algún patrón repetido de acción, proceso o estructura que inicialmente parece ser beneficioso, pero que en última instancia produce más malas consecuencias que resultados beneficiosos, y
- Una solución refactorizada que está claramente documentada, probada en la práctica real y repetible.
Vota por el antipatrón TDD que has visto "en la naturaleza" demasiadas veces.
La publicación del blog de James Carr y la discusión relacionada sobre testdrivendevelopment yahoogroup
Si ha encontrado uno "sin nombre" ... publíquelos también. Una publicación por antipatrón, por favor, para que los votos cuenten para algo.
Mi interés personal es encontrar el subconjunto top-n para poder discutirlos en una reunión de almuerzo en un futuro próximo.
unit-testing
tdd
anti-patterns
Gishu
fuente
fuente
Respuestas:
Ciudadanos de segunda clase : el código de prueba no se refactoriza tan bien como el código de producción, que contiene una gran cantidad de código duplicado, lo que dificulta el mantenimiento de las pruebas.
fuente
The Free Ride / Piggyback - James Carr, Tim Ottinger
En lugar de escribir un nuevo método de caso de prueba para probar otra característica / funcionalidad distinta , una nueva afirmación (y sus acciones correspondientes, es decir, los pasos Actuar de AAA) se acompaña en un caso de prueba existente .
fuente
true
después de cada posible llamada de mutador. Por lo tanto, querrá verificar que cada invariante estétrue
después de cada combinación de datos mutantes y de entrada que esté probando. Pero querrá reducir la duplicación y asegurarse de verificar todos los invariantes, incluidos los que actualmente no causan fallas en las pruebas. Entonces los pones a todos en unacheckInvariants()
función de verificación y los usas en cada prueba. El código cambia y se agrega otro invariante. Pones eso en la función también, por supuesto. Pero es un freerider.Camino feliz
La prueba se mantiene en caminos felices (es decir, resultados esperados) sin probar límites y excepciones.
JUnit Antipatterns
fuente
El héroe local
Un caso de prueba que depende de algo específico del entorno de desarrollo en el que se escribió para ejecutarse. El resultado es que la prueba pasa a los cuadros de desarrollo, pero falla cuando alguien intenta ejecutarlo en otro lugar.
La dependencia oculta
Estrechamente relacionado con el héroe local, una prueba unitaria que requiere que algunos datos existentes se hayan poblado en algún lugar antes de que se ejecute la prueba. Si esos datos no se poblaron, la prueba fallará y dejará poca indicación al desarrollador de lo que quería, o por qué ... obligándolos a cavar a través de acres de código para averiguar de dónde se suponía que provenían los datos que estaba usando.
Lamentablemente, esto se ha visto demasiadas veces con archivos .dlls antiguos que dependen de archivos .ini nebulosos y variados que están constantemente fuera de sincronización en cualquier sistema de producción dado, y mucho menos en su máquina sin una amplia consulta con los tres desarrolladores responsables de esos archivos dll. Suspiro.
fuente
Pandilla de cadena
Un par de pruebas que deben ejecutarse en un cierto orden, es decir, una prueba cambia el estado global del sistema (variables globales, datos en la base de datos) y las siguientes pruebas dependen de ello.
A menudo ves esto en las pruebas de bases de datos. En lugar de hacer una reversión
teardown()
, las pruebas confirman sus cambios en la base de datos. Otra causa común es que los cambios en el estado global no están envueltos en bloques try / finally que se limpian en caso de que falle la prueba.fuente
La burla
A veces, burlarse puede ser bueno y útil. Pero a veces los desarrolladores pueden perderse y en su esfuerzo por burlarse de lo que no se está probando. En este caso, una prueba unitaria contiene tantos simulacros, trozos y / o falsificaciones que el sistema que se está probando ni siquiera se está probando, sino que los datos devueltos de los simulacros son lo que se está probando.
Fuente: publicación de James Carr.
fuente
El guardián silencioso - ¿Kelly?
Una prueba que pasa si se lanza una excepción ... incluso si la excepción que realmente ocurre es diferente a la que el desarrollador pretendía.
Ver también: Secret Catcher
fuente
El inspector
Una prueba de unidad que viola la encapsulación en un esfuerzo por lograr una cobertura de código del 100%, pero sabe tanto sobre lo que está sucediendo en el objeto que cualquier intento de refactorización romperá la prueba existente y requerirá que cualquier cambio se refleje en la unidad prueba.
'¿cómo pruebo mis variables miembro sin hacerlas públicas ... solo para pruebas unitarias?'
fuente
Configuración excesiva : James Carr
Una prueba que requiere una configuración enorme para incluso comenzar a probar. A veces, se utilizan varios cientos de líneas de código para preparar el entorno para una prueba, con varios objetos involucrados, lo que puede dificultar determinar realmente lo que se prueba debido al "ruido" de toda la configuración que se está realizando. (Src: publicación de James Carr )
fuente
Sonda anal
Una prueba que tiene que usar formas insanas, ilegales o poco saludables para realizar su tarea, como: leer campos privados usando setAccessible (verdadero) de Java o extender una clase para acceder a campos / métodos protegidos o tener que poner la prueba en un paquete determinado para acceder paquete de campos / métodos globales.
Si ve este patrón, las clases bajo prueba utilizan demasiada ocultación de datos.
La diferencia entre esto y The Inspector es que la clase bajo prueba intenta ocultar incluso las cosas que necesita probar. Por lo tanto, su objetivo no es lograr una cobertura de prueba del 100%, sino poder probar cualquier cosa. Piense en una clase que solo tiene campos privados, un
run()
método sin argumentos y sin captadores. No hay forma de probar esto sin romper las reglas.Comentario de Michael Borgwardt: Esto no es realmente un antipatrón de prueba, es pragmatismo para tratar las deficiencias en el código que se está probando. Por supuesto, es mejor corregir esas deficiencias, pero eso puede no ser posible en el caso de bibliotecas de terceros.
Aaron Digulla: Estoy de acuerdo. Quizás esta entrada sea realmente más adecuada para un wiki "JUnit HOWTO" y no para un antipatrón. Comentarios?
fuente
La prueba sin nombre - Nick Pellow
La prueba que se agrega para reproducir un error específico en el rastreador de errores y cuyo autor cree que no garantiza un nombre propio. En lugar de mejorar una prueba existente y faltante, se crea una nueva prueba llamada testForBUG123.
Dos años después, cuando esa prueba falla, es posible que primero deba intentar encontrar BUG-123 en su rastreador de errores para descubrir la intención de la prueba.
fuente
El empuje lento
Una prueba unitaria que funciona increíblemente lenta. Cuando los desarrolladores lo inician, tienen tiempo para ir al baño, fumar o, lo que es peor, comenzar la prueba antes de irse a casa al final del día. (Src: publicación de James Carr )
también conocido como las pruebas que no se ejecutarán con tanta frecuencia como deberían
fuente
La mariposa
Debe probar algo que contenga datos que cambien todo el tiempo, como una estructura que contenga la fecha actual, y no hay forma de fijar el resultado en un valor fijo. La parte fea es que no te importa este valor en absoluto. Simplemente hace que su prueba sea más complicada sin agregar ningún valor.
El murciélago de su ala puede causar un huracán en el otro lado del mundo. - Edward Lorenz, El efecto mariposa
fuente
System.DateTime.Now
, además de tener pruebas unitarias más simples o más deterministas?toString()
a un objeto que no sobrescribe el método. Eso le dará la identificación del objeto que depende de la dirección de memoria. OtoString()
contiene la clave principal del objeto y eso cambia cada vez que ejecuta la prueba. Hay tres formas de solucionar esto: 1. Cambie el código que está probando, 2. use regexp para eliminar las partes variables de los resultados de la prueba o 3. use herramientas poderosas para sobrescribir los servicios del sistema para que devuelvan resultados predecibles.La prueba de parpadeo (Fuente: Romilly Cocking)
Una prueba que ocasionalmente falla, no en momentos específicos, y generalmente se debe a las condiciones de carrera dentro de la prueba. Suele ocurrir al probar algo que es asíncrono, como JMS.
Posiblemente un súper set para el antipatrón ' Wait and See ' y el antipatrón ' The Sleeper '.
La compilación falló, bueno, simplemente ejecute la compilación nuevamente. - Desarrollador anónimo
fuente
Espera y verás
Una prueba que ejecuta algún código de configuración y luego necesita 'esperar' una cantidad de tiempo específica antes de que pueda 'ver' si el código bajo prueba funcionó como se esperaba. Un testMethod que usa Thread.sleep () o equivalente es sin duda una prueba de "Esperar y ver".
Normalmente, puede ver esto si la prueba es un código de prueba que genera un evento externo al sistema, como un correo electrónico, una solicitud http o escribe un archivo en el disco.
Dicha prueba también puede ser un héroe local, ya que FALLARÁ cuando se ejecute en una caja más lenta o en un servidor de CI sobrecargado.
El antipatrón Wait and See no debe confundirse con The Sleeper .
fuente
Dispositivo compartido de forma inapropiada - Tim Ottinger
Varios casos de prueba en el dispositivo de prueba ni siquiera usan o necesitan la configuración / desmontaje. En parte debido a la inercia del desarrollador para crear un nuevo accesorio de prueba ... más fácil simplemente agregar un caso de prueba más a la pila
fuente
El gigante
Una prueba unitaria que, aunque está probando válidamente el objeto bajo prueba, puede abarcar miles de líneas y contener muchos casos de prueba. Esto puede ser un indicador de que el sistema bajo pruebas es un Objeto de Dios (publicación de James Carr).
Una señal segura de esto es una prueba que abarca más de unas pocas líneas de código. A menudo, la prueba es tan complicada que comienza a contener errores propios o escamosos.
fuente
Lo creeré cuando vea algunas GUI parpadeantes.
Una obsesión / fijación poco saludable con probar la aplicación a través de su GUI 'como un usuario real'.
"Debes entender que ver es creer, pero también saber que creer es ver". - Denis Waitley
fuente
El durmiente, también conocido como Monte Vesubio - Nick Pellow
Una prueba que está destinada a FALLAR en un momento y fecha específicos en el futuro. Esto a menudo es causado por una verificación incorrecta de los límites cuando se prueba el código que usa un objeto Fecha o Calendario. A veces, la prueba puede fallar si se ejecuta a una hora muy específica del día, como la medianoche.
'The Sleeper' no debe confundirse con el antipatrón ' Wait And See '.
Ese código habrá sido reemplazado mucho antes del año 2000 - Muchos desarrolladores en 1960
fuente
El árbol muerto
Una prueba en la que se creó un código auxiliar, pero la prueba no se escribió realmente.
De hecho, he visto esto en nuestro código de producción:
Ni siquiera sé qué pensar al respecto.
fuente
me mordió esto hoy:
Piso mojado :
la prueba crea datos que persisten en alguna parte, pero la prueba no se limpia cuando finaliza. Esto hace que las pruebas (la misma prueba o posiblemente otras pruebas) fallen en ejecuciones de pruebas posteriores .
En nuestro caso, la prueba dejó un archivo en el directorio "temp", con permisos del usuario que ejecutó la prueba la primera vez. Cuando un usuario diferente intentó probar en la misma máquina: boom. En los comentarios en el sitio de James Carr, Joakim Ohlrogge se refirió a esto como el "Trabajador descuidado", y fue parte de la inspiración para "Sobras generosas". Me gusta más mi nombre (menos insultante, más familiar).
fuente
The Cuckoo - Frank Carver
Una prueba de unidad que se encuentra en un caso de prueba con varios otros, y disfruta del mismo proceso de configuración (potencialmente largo) que las otras pruebas en el caso de prueba, pero luego descarta algunos o todos los artefactos de la configuración y crea el suyo.
Síntoma avanzado de: accesorio compartido de forma inapropiada
fuente
The Secret Catcher - Frank Carver
Una prueba que a primera vista parece no estar haciendo pruebas, debido a la ausencia de afirmaciones. Pero "El diablo está en los detalles" ... la prueba realmente se basa en una excepción y se espera que el marco de prueba capture la excepción y la informe al usuario como una falla.
fuente
Assert.DoesNotThrow(SomeDelegateType act)
afirmación de estilo que se puede usar específicamente en casos como este. Encuentro esto menos asqueroso que tener un caso de prueba que tiene éxito cuando un constructor devuelve no nulo, pero falla cuando el constructor tira. Un constructor nunca devolverá nulo. (Nota: solo se aplica a idiomas en los que se garantiza que un constructor devolverá no nulo)El vándalo ambiental
Una prueba de 'unidad' que para varios 'requisitos' comienza a extenderse a su entorno, usando y configurando variables / puertos de entorno. Ejecutar dos de estas pruebas simultáneamente provocará excepciones de 'puerto no disponible', etc.
Estas pruebas serán intermitentes y dejarán que los desarrolladores digan cosas como "simplemente ejecútelo de nuevo".
Una solución que he visto es seleccionar aleatoriamente un número de puerto para usar. Esto reduce la posibilidad de un conflicto, pero claramente no resuelve el problema. Entonces, si puedes, siempre mofa el código para que realmente no asigne el recurso no compartible.
fuente
La prueba de Turing
Un caso de prueba generado automáticamente por una herramienta costosa que tiene muchas, muchas afirmaciones obtenidas de la clase bajo prueba usando un análisis de flujo de datos demasiado inteligente a la mitad. Llena a los desarrolladores a una falsa sensación de confianza de que su código está bien probado, eximiéndolos de la responsabilidad de diseñar y mantener pruebas de alta calidad. Si la máquina puede escribir las pruebas por usted, ¿por qué no puede sacar su dedo y escribir la aplicación misma?
Hola tonto. - La computadora más inteligente del mundo para nuevos aprendices (de un viejo cómic de Amiga).
fuente
La prueba del poste de cuarenta pies
Temerosos de acercarse demasiado a la clase que intentan evaluar, estas pruebas actúan a distancia, separadas por innumerables capas de abstracción y miles de líneas de código de la lógica que están comprobando. Como tales, son extremadamente frágiles y susceptibles a todo tipo de efectos secundarios que ocurren en el viaje épico hacia y desde la clase de interés.
fuente
Doppelgänger
Para probar algo, debe copiar partes del código que se está probando en una nueva clase con el mismo nombre y paquete, y debe usar classpath magic o un cargador de clases personalizado para asegurarse de que sea visible primero (para que su copia sea seleccionada arriba).
Este patrón indica una cantidad poco saludable de dependencias ocultas que no puede controlar desde una prueba.
Miré su cara ... ¡mi cara! Era como un espejo pero me helaba la sangre.
fuente
The Mother Hen - Frank Carver
Una configuración común que hace mucho más de lo que necesitan los casos de prueba reales. Por ejemplo, crear todo tipo de estructuras de datos complejas pobladas con valores aparentemente importantes y únicos cuando las pruebas solo afirman la presencia o ausencia de algo.
Síntoma avanzado de: accesorio compartido de forma inapropiada
No sé lo que hace ... Lo agrego de todos modos, por si acaso. - Desarrollador anónimo
fuente
La prueba de todo
No puedo creer que esto no se haya mencionado hasta ahora, pero las pruebas no deberían romper el Principio de Responsabilidad Única .
Me he encontrado con esto muchas veces, las pruebas que rompen esta regla son, por definición, una pesadilla para mantener.
fuente
Bateador de línea
En el primer vistazo, las pruebas cubren todo y las herramientas de cobertura de código lo confirman con el 100%, pero en realidad las pruebas solo golpean el código sin ningún análisis de salida.
código de cobertura vs alcanzable
fuente