unit-testing - los - lista de antipatrones
Catálogo de pruebas anti-patrones unitarios. (30)
anti-pattern : debe haber al menos dos elementos clave presentes para distinguir formalmente un anti-patrón real de un simple mal hábito, mala práctica o mala idea:
- Algunos patrones repetidos de acción, proceso o estructura que inicialmente parecen ser beneficiosos, pero en última instancia producen más consecuencias negativas que resultados beneficiosos, y
- Una solución refaccionada que está claramente documentada, probada en la práctica real y repetible.
Vota por el anti-patrón TDD que has visto "en la naturaleza" una vez demasiado.
La publicación del blog de James Carr y la discusión relacionada sobre testdrivendevelopment yahoogroup
Si has encontrado uno "sin nombre", postéalos también. Una publicación por anti-patrón, por favor, para que los votos cuenten para algo.
Mi interés personal es encontrar el subconjunto top-n para poder discutirlos en un almuerzo en un futuro cercano.
Se mordió por esto hoy:
Piso mojado
La prueba crea datos que se conservan en algún lugar, pero la prueba no se limpia cuando finaliza. Esto hace que las pruebas (la misma prueba, o posiblemente otras pruebas) fallen en las siguientes ejecuciones de prueba.
En nuestro caso, la prueba dejó un archivo en el directorio "temp", con los 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).
Accesorio inapropiado compartido - 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 dispositivo de prueba ... más fácil simplemente agregar un caso de prueba más a la pila
Bateador de linea
En el primer vistazo, las pruebas cubren todo y las herramientas de cobertura de código lo confirman en un 100%, pero en realidad las pruebas solo alcanzan el código sin ningún análisis de salida.
Chain Gang
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 la siguiente prueba (s) depende de ello.
A menudo se ve esto en las pruebas de base de datos. En lugar de hacer una reversión en teardown()
, las pruebas confirman sus cambios en la base de datos. Otra causa común es que los cambios en el estado global no se envuelven en los bloques try / finally que se limpian si la prueba falla.
Ciudadanos de segunda clase : el código de prueba no está tan refaccionado como el código de producción, ya que contiene una gran cantidad de códigos duplicados, lo que dificulta el mantenimiento de las pruebas.
Configuración excesiva - James Carr
Una prueba que requiere una gran configuración para incluso comenzar a probar. Algunas 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 hacer que sea difícil determinar realmente lo que se está probando debido al "ruido" de toda la configuración que está ocurriendo. (Src: la publicación de James Carr )
Doppelgänger
Para probar algo, tiene que copiar partes del código bajo prueba en una nueva clase con el mismo nombre y paquete, y tiene que usar classpath magic o un cargador de clases personalizado para asegurarse de que esté visible primero (para que se escoja su copia) 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 hacía que mi sangre se congelara.
El Cuco - 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 propio.
Síntoma avanzado de: Accesorio inapropiado compartido
El arbol muerto
Una prueba en la que se creó un código auxiliar, pero en realidad no se escribió.
De hecho, he visto esto en nuestro código de producción:
class TD_SomeClass {
public void testAdd() {
assertEquals(1+1, 2);
}
}
Ni siquiera sé qué pensar sobre eso.
El gigante
Una prueba de unidad 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 prueba es un Objeto de Dios (la publicación de James Carr).
Un signo seguro para esta 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.
El guardián secreto - Frank Carver
Una prueba que a primera vista parece no hacer ninguna prueba, debido a la ausencia de afirmaciones. Pero "El demonio está en los detalles" ... la prueba realmente se basa en una excepción que se va a lanzar y espera que el marco de pruebas capture la excepción y la informe al usuario como un error.
[Test]
public void ShouldNotThrow()
{
DoSomethingThatShouldNotThrowAnException();
}
El heroe 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 los cuadros de desarrollo, pero falla cuando alguien intenta ejecutarlo en otro lugar.
La dependencia oculta
Muy relacionado con el héroe local, una prueba unitaria que requiere que algunos datos existentes se hayan completado en algún lugar antes de que se ejecute la prueba. Si esos datos no se rellenaron, la prueba fallará y dejará poca indicación al desarrollador de lo que quería, o por qué ... forzándolos a investigar en acres de código para averiguar de dónde provendrían los datos que estaba usando.
Lamentablemente, esto lo he visto demasiadas veces con archivos .dll antiguos que dependen de nebulosos y variados archivos .ini que están constantemente desincronizados en cualquier sistema de producción dado, y mucho menos existentes en su máquina sin una consulta extensa con los tres desarrolladores responsables de esos archivos DLL. Suspiro.
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 mucho sobre lo que está sucediendo en el objeto que cualquier intento de refactorizar romperá la prueba existente y requerirá que cualquier cambio se refleje en la prueba de unidad.
''¿Cómo pruebo mis variables de miembro sin hacerlas públicas ... solo para pruebas de unidad?''
El lento empuje
Una prueba unitaria que se ejecuta increíblemente lenta. Cuando los desarrolladores lo inician, tienen tiempo para ir al baño, fumar un cigarrillo o, peor aún, comenzar la prueba antes de irse a casa al final del día. (Src: la publicación de James Carr )
También conocido como las pruebas que no se ejecutan con la frecuencia que deberían
El vandalismo ambiental
Una prueba de ''unidad'' que para diversos ''requisitos'' comienza a extenderse a su entorno, utilizando y configurando variables / puertos de entorno. Ejecutar dos de estas pruebas simultáneamente causará excepciones de ''puerto no disponible'', etc.
Estas pruebas serán intermitentes y dejarán a los desarrolladores diciendo cosas como ''solo ejecútalo 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 simula el código para que no asigne el recurso no compartible.
Espera y verás
Una prueba que ejecuta algún código de configuración y luego necesita "esperar" una cantidad específica de tiempo antes de que pueda "ver" si el código bajo prueba funcionó como se esperaba. Un método de prueba que utiliza Thread.sleep () o equivalente es, sin duda, una prueba de "Esperar y ver".
Por lo general, puede ver esto si la prueba está probando un código que genera un evento externo al sistema, como un correo electrónico, una solicitud http o escribe un archivo en el disco.
Una prueba de este tipo 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 .
Feliz camino
La prueba se mantiene en caminos felices (es decir, resultados esperados) sin pruebas de límites y excepciones.
La burla
A veces la burla puede ser buena 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 de unidad contiene tantos simulacros, talones y / o falsificaciones que el sistema bajo prueba ni siquiera se está probando en absoluto, en lugar de eso, lo que se está probando es la información devuelta por simulacros.
Fuente: publicación de James Carr.
La madre gallina - 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 con valores aparentemente importantes y únicos cuando las pruebas solo afirman la presencia o ausencia de algo.
Síntoma avanzado de: Accesorio inapropiado compartido
No sé lo que hace ... Lo estoy agregando de todos modos, por si acaso. - Desarrollador Anónimo
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 su prueba 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
La prueba de parpadeo (Fuente: Romilly Cocking)
Una prueba que solo falla ocasionalmente, no en momentos específicos, y generalmente se debe a las condiciones de la carrera dentro de la prueba. Normalmente ocurre cuando se prueba algo que es asíncrono, como JMS.
Posiblemente un superconjunto para el anti-patrón " Wait and See " y el anti-patrón " The Sleeper ".
La compilación falló, bueno, ejecuta la compilación de nuevo. - Desarrollador Anónimo
La prueba de todo
No puedo creer que esto no haya sido mencionado hasta ahora, pero las pruebas no deben romper el Principio de Responsabilidad Única .
Me he topado con esto tantas veces, las pruebas que rompen esta regla son, por definición, una pesadilla para mantener.
La prueba de turing
Un testcase generado automáticamente por una herramienta costosa que tiene muchas, muchas afirmaciones obtenidas de la clase bajo prueba que utiliza un análisis de flujo de datos demasiado inteligente por la mitad. Acosa a los desarrolladores con una falsa sensación de confianza de que su código está bien probado, absolvié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 en sí misma?
Hola tonto. - La computadora más inteligente del mundo para un nuevo aprendiz (de un antiguo cómic de Amiga).
La prueba del poste de cuarenta pies
Con el temor de acercarse demasiado a la clase que intentan probar, 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.
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 que falta, se crea una nueva prueba llamada testForBUG123.
Dos años más tarde, cuando la prueba falla, es posible que primero deba intentar encontrar BUG-123 en su rastreador de errores para descubrir la intención de la prueba.
Lo creeré cuando vea algunas interfaces gráficas de usuario
Una obsesión / fijación poco saludable con probar la aplicación a través de su GUI ''como un usuario real''
Probar reglas de negocio a través de la GUI es una forma terrible de acoplamiento. Si escribe miles de pruebas a través de la GUI y luego cambia su GUI, se rompen miles de pruebas.
En su lugar, pruebe solo las cosas de la GUI a través de la GUI y acople la GUI a un sistema ficticio en lugar del sistema real, cuando ejecute esas pruebas. Pruebe las reglas de negocio a través de una API que no implique la GUI. - Bob Martin
"Debes entender que ver es creer, pero también saber que creer es ver". - Denis Waitley
Sonda anal
Una prueba que tiene que usar formas insanas, ilegales o de otro modo poco saludables para realizar su tarea como: leer campos privados usando setAccessible(true) 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 global de campos / métodos.
Si ve este patrón, las clases bajo prueba usan 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 en absoluto. Piense en una clase que solo tiene campos privados, un método run()
sin argumentos y sin captadores. No hay manera de probar esto sin romper las reglas.
Comentario de Michael Borgwardt: Esto no es realmente una prueba antipatrónica, es un 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. Tal vez esta entrada sea realmente mejor para un wiki "JUnit HOWTO" y no un antipattern. ¿Comentarios?
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 de la Ley de AAA) se desarrolla en un caso de prueba existente.
The Silent Catcher - Kelly?
Una prueba que pasa si se lanza una excepción ... incluso si la excepción que realmente ocurre es una que es diferente a la que el desarrollador pretendía.
Ver También: Secret Catcher
[Test]
[ExpectedException(typeof(Exception))]
public void ItShouldThrowDivideByZeroException()
{
// some code that throws another exception yet passes the test
}
The Sleeper, también conocido como el Monte Vesubio - Nick Pellow
Una prueba que está destinada a FALLAR en una fecha y hora específicas en el futuro. A menudo, esto se debe a la verificación de límites incorrectos 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 anti-patrón '' Wait And See ''.
Ese código habrá sido reemplazado mucho antes del año 2000 - Muchos desarrolladores en 1960