Catálogo de antipatrones de pruebas unitarias

203

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.

Gishu
fuente
Aaron, pareces estar en todo este :) ¿Sería una buena idea agregar las etiquetas o lemas como comentarios para que podamos tener menos desplazamiento ... ¿qué dices?
Gishu
1
Esto está saliendo bastante bien ... gracias chicos y chicas. Sigue viniendo ... uno de los mensajes SO más informativos en mi humilde opinión
Gishu
2
+1 amo este hilo !!! ¡Y la mayoría de estos son tan ciertos y prevalentes también!
Chii
Buen hilo, ¿por qué esta wiki de la comunidad?
Quibblesome
2
Porque es una especie de encuesta: no querrás cosechar representantes solo porque publicaste el tipo más común de antipatrón;)
Gishu

Respuestas:

70

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.

Ilja Preuß
fuente
67

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 .

Aaron Digulla
fuente
15
Sí, ese es mi favorito. Lo hago todo el tiempo. Oh ... espera ... dijiste que esto era algo malo . :-)
guidoism
1
No estoy tan seguro de que sea un antipatrón. Todos los invariantes deben estar truedespués de cada posible llamada de mutador. Por lo tanto, querrá verificar que cada invariante esté truedespué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 una checkInvariants()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.
Raedwald
2
@Raedwald: con el tiempo, el nombre de la prueba ya no coincide con todas las cosas que prueba. También tienes algunas sacudidas debido a las pruebas entrelazadas; una falla no señala la causa exacta de la falla. Por ejemplo, un ejemplo canónico de esta prueba leería algo como Opaque Superset of all Arrange steps >> Act >> Assert A >> Act more more >> Assert B >> Act more more >> Assert C. Ahora idealmente si A y C son roto, debería ver 2 fallas de prueba. Con la prueba anterior, solo vería una, luego repara A y en la próxima ejecución, le diría que ahora C está roto. ahora imagine 5-6 pruebas distintas fusionadas juntas ..
Gishu
1
"el nombre de la prueba ya no coincide con todas las cosas que prueba" Solo si la prueba se nombra para la condición de publicación que originalmente estaba presente. Si nombra la combinación de nombre de método, estado de configuración y datos de entrada (argumentos de método), no hay problema.
Raedwald
"una falla no señala la causa exacta de la falla" ninguna falla de aserción indica la causa de una falla. Eso requiere profundizar en los detalles de implementación: depuración para una falla de regresión, su conocimiento del estado de desarrollo para algunos trabajos TDD.
Raedwald
64

Camino feliz

La prueba se mantiene en caminos felices (es decir, resultados esperados) sin probar límites y excepciones.

JUnit Antipatterns

Geoglifo
fuente
Causa: limitaciones de tiempo exageradas o flojera evidente. Solución refactorizada: tómese un tiempo para escribir más pruebas para deshacerse de los falsos positivos. La última causa necesita un látigo. :)
Spoike
59

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.

annakata
fuente
Ese es un buen ejemplo del acrónimo de desarrollador WOMPC. "Funciona en mi PC!" (por lo general, se dice que le quite los probadores de la espalda).
Joris Timmermans,
58

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.

Aaron Digulla
fuente
este es simplemente desagradable. Rompe las pruebas debe ser una noción independiente. Pero lo he leído en varios lugares ... supongo que 'TDD popular' está bastante desordenado
Gishu
56

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.

Gishu
fuente
2
Creo que la causa de esto es que su clase bajo prueba tiene demasiadas dependencias. La alternativa refactorizada es extraer código que pueda aislarse.
Spoike
@Spoike; Si está en una arquitectura en capas que realmente depende del papel de la clase; Algunas capas tienden a tener más dependencias que otras.
krosenvold
Recientemente, en un respetado blog, vi la creación de una configuración de entidad simulada que se devolverá desde un repositorio simulado. WTF? ¿Por qué no simplemente instanciar una entidad real en primer lugar? Yo mismo, acabo de quemarme por una interfaz simulada donde mi implementación arroja NotImplementedExceptions por todas partes.
Thomas Eyde
40

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

[Test]
[ExpectedException(typeof(Exception))]
public void ItShouldThrowDivideByZeroException()
{
   // some code that throws another exception yet passes the test
}
Gishu
fuente
Ese es complicado y peligroso (es decir, te hace pensar que probaste código que siempre explota cada vez que se ejecuta). Es por eso que trato de ser específico tanto sobre una clase de excepción como sobre algo único dentro del mensaje.
Joshua Cheek
34

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?'

Gishu
fuente
2
Causa: dependencia absoluta de las pruebas de caja blanca. Existen herramientas para generar este tipo de pruebas como Pex en .NET. Solución refactorizada: pruebe el comportamiento y, si realmente necesita verificar los valores límite, deje que las herramientas automatizadas generen el resto.
Spoike
1
Antes de que Moq apareciera, tuve que abandonar los marcos burlones en favor de escribir a mano mis simulacros. Era demasiado fácil vincular mis pruebas a la implementación real, haciendo que cualquier refactorización fuera casi imposible. No puedo notar la diferencia, aparte de con Moq, rara vez hago este tipo de errores.
Thomas Eyde
34

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 )

Gishu
fuente
Entiendo que la configuración de prueba excesiva generalmente apunta a a) código mal estructurado ob) burla insuficiente, ¿correcto?
Topher Hunt
Bueno, cada situación podría ser diferente. Podría deberse a un alto acoplamiento. Pero, por lo general, se trata de una especificación excesiva, especificando (expectativas falsas) a todos y cada uno de los colaboradores en el escenario; esto combina la prueba con la implementación y los hace frágiles. Si la llamada al colaborador es un detalle incidental de la prueba, no debe estar en la prueba. Esto también ayuda a mantener la prueba corta y legible.
Gishu
32

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?

Aaron Digulla
fuente
¿No es esto lo mismo que el Inspector?
Gishu
1
Hmm ... esta línea "la clase bajo prueba trata de ocultar incluso las cosas que necesitas probar" indica una lucha de poder entre la clase y la prueba. Si debe probarse ... debe ser accesible públicamente de alguna manera ... a través del comportamiento / interfaz de clase ... esto de alguna manera huele a una brecha en la encapsulación
Gishu
2
npellow: Maven2 tiene un complemento para eso, ¿no?
Aaron Digulla
1
Esto no es realmente un antipatrón de prueba, es pragmatismo lidiar con 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.
Michael Borgwardt
1
IDK, debe tener algún tipo de efecto secundario. Probaría el efecto secundario. No estoy seguro de lo que quiere decir sobre probar API de terceros, diría que debe incluir eso en su propio código que puede probar que se usó correctamente, luego intente probar ese código contra la API de terceros. No prueba la unidad del código de terceros.
Joshua Cheek
26

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.

npellow
fuente
77
Tan verdadero. Aunque eso es un poco más útil que una prueba llamada "TestMethod"
NikolaiDante
8
a menos que los cambios BugTracker, y de que pierda el antiguo seguidor y sus identificadores de emisión ... así PROYECTO-123 ya no significa nada ....
Chii
25

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

Gishu
fuente
Algunas pruebas se ejecutan lentamente por su propia naturaleza. Si decide no ejecutarlos con tanta frecuencia como los demás, asegúrese de que al menos se ejecuten en un servidor CI con la mayor frecuencia posible.
Chris Vest
Esta es una pregunta obvia, pero ¿cuáles son las formas más generales de solucionar esto?
Topher Hunt
Esto inicialmente parece beneficioso, ¿eh?
Kev
1
@TopherHunt Normalmente, las pruebas son lentas porque tienen una dependencia costosa (es decir, sistema de archivos, base de datos). El truco es analizar las dependencias hasta que vea el problema, luego empujar la dependencia hacia arriba en la pila de llamadas. Escribí un estudio de caso en el que mis estudiantes 'tomaron su conjunto de pruebas unitarias de 77 segundos a 0.01 segundos arreglando sus dependencias: github.com/JoshCheek/fast_tests
Joshua Cheek
20

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

Aaron Digulla
fuente
¿Cuál es el antipatrón aquí: cómo se ve una prueba como esta? ¿Hay alguna solución? ¿Hay alguna ventaja discutible en el código bajo prueba para factorizar una dependencia como System.DateTime.Now, además de tener pruebas unitarias más simples o más deterministas?
Merlyn Morgan-Graham
1
En Java, un ejemplo sería llamar 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. O toString()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.
Aaron Digulla
La causa subyacente de este antipatrón es que al código bajo prueba no le importa cuánto esfuerzo podría ser probarlo. Entonces, el capricho de un desarrollador es el ala de la mariposa que causa problemas en otros lugares.
Aaron Digulla
19

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

Stuart
fuente
@Stuart: un video imperdible que describe esto es "Auto atascado - ¡Pruébalo ahora!" videosift.com/video/… Este patrón también podría llamarse "¡Pruébelo ahora!", o simplemente - "The Flakey Test"
npellow
1
Una vez escribí una prueba para un PRGN que aseguraba una distribución adecuada. Ocasionalmente, fallaría al azar. Imagínate. :-)
Chris Vest
1
¿No sería una buena prueba? Si alguna vez falla una prueba, debe localizar el origen del problema. Luché con alguien por una prueba que falló entre las 9 p. M. Y la medianoche. Dijo que era aleatorio / intermitente. Finalmente se remontó a un error relacionado con las zonas horarias. Imagínate.
Trenton
@ Christian Vest Hansen: ¿no podrías sembrarlo?
Andrew Grimm
@trenton Es solo una buena prueba tener si los desarrolladores pueden molestarse en rastrearlo, en lugar de simplemente ignorarlo (que pueden salirse con la suya, ya que pasa la mayor parte del tiempo).
Will Sheppard
19

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 .

npellow
fuente
Hmm ... bueno, uso algo como esto. ¿De qué otra forma podría probar el código multiproceso?
Gishu
@Gishu, ¿realmente quieres probar múltiples subprocesos que se ejecutan simultáneamente? Intento realizar una prueba unitaria, independientemente de lo que haga el método run () de forma aislada. Una manera fácil de hacer esto es llamando a run (), que bloqueará, en lugar de start (), de la prueba de la unidad.
npellow
@Gishu utiliza CountDownLatches, semáforos, condiciones o similares, para que los hilos se comuniquen entre sí cuando puedan pasar al siguiente nivel.
Chris Vest
Un ejemplo: madcoderspeak.blogspot.com/2008/11/… Brew button evt. El observador está sondeando a intervalos y provocando eventos cambiados ... en cuyo caso agrego un retraso para que los hilos de votación tengan la oportunidad de ejecutarse antes de que finalice la prueba.
Gishu
Creo que el enlace de la caricatura está roto.
Andrew Grimm
17

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

Gishu
fuente
1
También puede ser que la clase bajo prueba esté tratando de hacer demasiado.
Mike Two
16

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.

Gishu
fuente
15

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'.

Probar las reglas comerciales 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, miles de pruebas se rompen.
Por el contrario, 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

Gishu
fuente
1
Si pensabas que flashear las GUI es incorrecto, vi a alguien que escribió una prueba de jUnit que inició la GUI y necesitaba la interacción del usuario para continuar. Colgó el resto del conjunto de pruebas. ¡Demasiado para la automatización de pruebas!
Spoike
Estoy en desacuerdo. Las pruebas de GUI son difíciles, pero también son una fuente de errores. No probarlos es simplemente vago.
Ray
3
El punto aquí es que no debe probar las GUI, sino que no debe probar solo a través de la GUI. Puede realizar pruebas 'sin cabeza' sin la GUI. Mantenga la GUI lo más delgada posible - use un sabor de MVP - luego podrá salirse sin probarlo en absoluto. Si encuentra que hay errores que surgen en la delgada capa de GUI todo el tiempo, cúbralo con pruebas ... pero la mayoría de las veces, no creo que valga la pena el esfuerzo. Los errores de "cableado" de la GUI suelen ser más fáciles de solucionar ...
Gishu
@Spoike: las pruebas manuales guiadas no son malas, ni está usando jUnit (o cualquier otro marco de pruebas unitarias) para conducir pruebas automatizadas que no son pruebas unitarias. Simplemente no debe ponerlos en el mismo proyecto, ni tratarlos como pruebas unitarias (por ejemplo, ejecutar constantemente o después de cada compilación).
Merlyn Morgan-Graham
1
@ MerlynMorgan-Graham Estoy de acuerdo, y no quise decir que no debería probar la GUI. La convicción de los miembros del equipo de que estaba bien mezclar las pruebas manuales guiadas con las automáticas, me inquietaba. Más tarde descubrí que era una excelente manera de hacer que todos los que no están acostumbrados a TDD dejen de usarlo. Me parece que mezclar pruebas funcionales (que son volátiles) con pruebas unitarias (que se supone que son estables) es malo si desea seguir el proceso TDD.
Spoike
14

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

npellow
fuente
Prefiero llamar a esto un volcán inactivo :) ... pero sé de lo que estás hablando ... por ejemplo, una fecha elegida como fecha futura para una prueba en el momento de la escritura se convertirá en una fecha presente / pasada cuando esa fecha pasa ... rompiendo la prueba. ¿Podría publicar un ejemplo ... solo para ilustrar esto?
Gishu
@Gishu - +1. Estaba pensando lo mismo, pero no podía decidir entre los dos.
Actualicé
11

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:

class TD_SomeClass {
  public void testAdd() {
    assertEquals(1+1, 2);
  }
}

Ni siquiera sé qué pensar al respecto.

Reverendo Gonzo
fuente
8
:) - también conocido como Process Backdoor.
Gishu
1
Recientemente tuvimos un ejemplo de esto en una prueba y un método bajo prueba que se refactorizó repetidamente. Después de algunas iteraciones, la prueba se convirtió en una llamada al método bajo prueba. Y debido a que el método ahora devuelve nulo, no hubo afirmaciones para afirmar. Básicamente, la prueba fue simplemente asegurarse de que el método no arrojara una excepción. No importaba si realmente hacía algo útil o correcto. Lo encontré en la revisión de código y pregunté: "Entonces ... ¿qué estamos probando aquí?"
Marvo
11

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

Zac Thompson
fuente
Puede usar la regla de carpeta temporal de junit para evitar pisos mojados.
DaveFar
Este tipo de se relaciona con un anti patrón de Integración Continua. En CI, cada desarrollador debe tener su propio espacio de trabajo y recursos, y la máquina de compilación también debe ser su propio entorno. Luego evitas cosas como problemas de permisos (o tal vez terminas ocultándolos para que solo aparezcan en producción)
Marvo
11

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

Gishu
fuente
10

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.

[Test]
public void ShouldNotThrow()
{
   DoSomethingThatShouldNotThrowAnException();
}
Gishu
fuente
2
De hecho, esto puede ser una prueba válida, en mi opinión, especialmente como una prueba de regresión.
Ilja Preuß
Lo siento, nuevamente confundí esto con Silent Catcher ... las pruebas unitarias deben indicar claramente la intención sobre lo que se está probando en lugar de decir 'esto debería funcionar' ... (+1 tp algo es mejor que nada. especialmente si estás en una regresión heredada país)
Gishu
1
En este tipo de pruebas, al menos capto Exception y lo asigno a una variable. Entonces afirmo por no nulo.
Thomas Eyde
44
Algunos marcos tienen una 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)
Merlyn Morgan-Graham
10

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.

gcrain
fuente
@gcrain .. las pruebas deben ser deterministas. En mi opinión, un mejor enfoque sería utilizar un puerto 'conocido en el equipo' para las pruebas y la limpieza antes y después de la prueba correctamente, de modo que siempre esté disponible ...
Gishu
1
@gishu: el problema no es que no haya métodos setup () y teardown () para manejar el uso de estos puertos. el problema es, por ejemplo, ejecutar un servidor CI y ejecutar varias versiones de la prueba al mismo tiempo, intentando usar los mismos números de puerto codificados en la prueba
gcrain
10

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

bhumphreys
fuente
10

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.

bhumphreys
fuente
9

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.

Aaron Digulla
fuente
7

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

Gishu
fuente
7

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.

thegreendroid
fuente
6

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

revs Ruslan Dzhabbarov
fuente