¿Cuál es el valor de verificar en las pruebas unitarias fallidas?

13

Si bien hay formas de evitar que se ejecuten las pruebas unitarias, ¿cuál es el valor de verificar las pruebas unitarias que fallan?

Usaré un ejemplo simple: mayúsculas y minúsculas. El código actual distingue entre mayúsculas y minúsculas. Una entrada válida en el método es "Cat" y devolvería una enumeración de Animal.Cat. Sin embargo, la funcionalidad deseada del método no debe ser sensible a mayúsculas y minúsculas. Entonces, si el método descrito se pasó "gato", posiblemente podría devolver algo como Animal.Null en lugar de Animal.Cat y la prueba unitaria fallaría. Aunque un simple cambio de código haría que esto funcionara, solucionar un problema más complejo puede llevar semanas, pero identificar el error con una prueba unitaria podría ser una tarea menos compleja.

La aplicación que se está analizando actualmente tiene 4 años de código que "funciona". Sin embargo, las discusiones recientes sobre las pruebas unitarias han encontrado fallas en el código. Algunos solo necesitan documentación de implementación explícita (por ejemplo, mayúsculas o minúsculas) o código que no ejecute el error en función de cómo se llama actualmente. Pero se pueden crear pruebas unitarias ejecutando escenarios específicos que harán que se vea el error y sean entradas válidas.

¿Cuál es el valor de verificar las pruebas unitarias que ejercitan el error hasta que alguien pueda solucionar el código?

¿Debería marcarse esta prueba unitaria con ignorar, prioridad, categoría, etc., para determinar si una compilación fue exitosa en base a las pruebas ejecutadas? Finalmente, la prueba unitaria debe crearse para ejecutar el código una vez que alguien lo arregle.

Por un lado, muestra que los errores identificados no se han corregido. Por otro lado, podría haber cientos de pruebas unitarias fallidas que aparecen en los registros y eliminar las que deberían fallar frente a las fallas debido a un registro de código sería difícil de encontrar.

Jim G.
fuente
Esa es una forma de aumentar esos números de cobertura de prueba.
JeffO
Si ya se esforzó por escribir la prueba de la unidad, ¿por qué querría tener que volver a escribirla cuando decida solucionar el problema? El hecho de que esté registrado no significa que deba ejecutarse en la suite. (Puede hacer una categoría para "Problemas conocidos" y tratar esas pruebas como una lista de tareas pendientes / TODO).
Caleb

Respuestas:

17

No me gustan las pruebas de unidades rotas registradas porque producen ruido innecesario. Después de cada prueba de unidad, tendría que verificar todos los problemas fallidos (rojo). ¿Es rojo porque hay un nuevo problema o porque hay un viejo abierto para hacer / arreglar? Esto no está bien si hay más de 20 pruebas unitarias.

En cambio uso

  • [Ignore("Reason")]atributo que hace que el resultado sea amarillo o
  • throw new NotImplementedException()eso hace que el resultado sea gris

Nota: Estoy usando NUnit para .net. No estoy seguro de si la función "gris" está presente en otros marcos de prueba de unidad.

Entonces me gusta el siguiente significado de resultados de pruebas unitarias.

  • verde: todo terminado
  • gris: nuevas funciones planificadas que deben hacerse pero con baja prioridad
  • amarillo: errores no corregidos todavía. Debería arreglarse pronto
  • rojo: nuevos errores. Debe arreglarse de inmediato

Todo excepto "rojo" puede registrarse.

Para responder a la pregunta: hay más daño que valor al registrar "test-fallas rojas", pero la comprobación de "pruebas ignoradas amarillas" o "pruebas-NotImplemented-grises" puede ser útil como lista de tareas pendientes.

k3b
fuente
El problema que veo con este enfoque es que las pruebas ignoradas probablemente nunca serán reparadas. También podría simplemente eliminar todo el código de prueba, cuál sería la diferencia (estoy siendo un poco arrogante aquí)
Lovis
44
will probably never be fixedes una decisión política si quiere gastar efford en pruebas automatizadas o no. Con las "pruebas ignoradas" tienes la oportunidad de arreglarlas. Tirar "pruebas ignoradas" significa "abandonar las pruebas automatizadas poco a poco hasta que no haya más"
k3b
8

No voy a fingir que este es el estándar de la industria, pero reviso las pruebas interrumpidas como una forma de recordarme a mí oa mis otros miembros del proyecto que todavía hay un problema con el código o la prueba de la unidad en sí.

Supongo que una cosa a considerar es si sus políticas de desarrollo permiten pruebas fallidas sin penalización. Tengo un amigo que trabaja en una tienda que realiza un desarrollo basado en pruebas, por lo que siempre comienzan con pruebas fallidas ...

Tieson T.
fuente
55
Pero nunca debe registrarse en una prueba fallida, ya que su servidor de compilación no debe compilar un proyecto con una prueba rota.
CaffGeek
@Chad: La construcción y las pruebas son dos piezas separadas de un solo paso automatizado. El edificio asegura que todo se compila. La prueba garantiza que el resultado de la compilación sea válido. Mi interpretación de la pregunta no fue, "¿debo verificar el código que no se compila?" En cambio, fue, "¿debería registrar una prueba que sé que fallará?"
Unholysampler
1
Solo estaba agregando un punto a considerar, algunos servidores de compilación de integración continua ejecutan las pruebas, y si fallan, no se implementan. Con razón, como si la compilación falla, el código falla y no tiene sentido implementar un producto que se sepa que está dañado.
CaffGeek
@Chad: Correcto, me olvidé por completo de los servidores de CI. Eso definitivamente sería un punto a considerar. También vale la pena aclarar lo que entendemos por pruebas "rotas"; ¿son simplemente pruebas "malas" o la prueba falla porque la API cambió de alguna manera?
Tieson T.
La pregunta debería haber sido más clara. Debería ser La prueba se compilará, pero el resultado esperado fallará.
6

Las pruebas unitarias que fallan le dan al equipo de desarrollo visibilidad sobre lo que debe hacerse para cumplir con las especificaciones acordadas.

En resumen, las pruebas de unidades que fallan le dan al equipo una lista de "TODO".

Por esta razón, las pruebas unitarias fallidas son mucho mejores que ninguna prueba unitaria. *
La ausencia de pruebas unitarias deja al equipo de desarrollo en la oscuridad; Las especificaciones deben confirmarse repetidamente manualmente .

[* Siempre que las pruebas unitarias realmente prueben algo útil.]

Jim G.
fuente
2
Hay mejores formas de mantener una lista de tareas pendientes, por ejemplo, una pizarra, una aplicación de lista de tareas o un sistema de seguimiento de problemas. Es mucho más fácil usar un conjunto de pruebas si espera que pase siempre por completo, y cualquier falla de prueba que aparezca es un nuevo problema para solucionar de inmediato.
bdsl
6

El propósito de las pruebas unitarias es afirmar el comportamiento esperado de un sistema, no documentar defectos. Si usamos pruebas unitarias para documentar defectos, entonces se reduce su utilidad para afirmar el comportamiento esperado. La respuesta a la pregunta "¿Por qué falló esta prueba?" No es un simple "Oh, algo está roto que no esperaba estar roto". Se desconoce si la falla de la prueba es esperada o inesperada.

Aquí hay un párrafo del comienzo del capítulo 13 de Trabajo efectivo con código heredado :

Las pruebas unitarias automatizadas son una herramienta muy importante, pero no para encontrar errores, al menos no directamente. En general, las pruebas automatizadas deben especificar un objetivo que nos gustaría cumplir o intentar preservar el comportamiento que ya existe. En el flujo natural del desarrollo, las pruebas que especifican se convierten en pruebas que preservan . Encontrará errores, pero generalmente no es la primera vez que se ejecuta una prueba. Encontrará errores en ejecuciones posteriores cuando cambie el comportamiento que no esperaba.

Matthew Rodatus
fuente
3

Pero los rotos que identifican errores en un nuevo proyecto, nombrado como tal. De esa manera, puede ver que DEBEN romperse ... A medida que se reparan, se volverán verdes y se trasladarán al conjunto de pruebas normal.

NOTA: Ese proyecto tendría que configurarse para que no se construya en el servidor de compilación, si su servidor de compilación evita los registros que rompen la compilación (suponiendo que defina una compilación interrumpida como una en la que no pasan todas las pruebas)

CaffGeek
fuente
+1, aunque no hay respuesta si hay que registrarse o no, hay un argumento importante: construir servidor
k3b
Prefiero usar un atributo para marcar dicha prueba en lugar de moverla a un proyecto separado.
CodesInChaos
2

Las pruebas unitarias deben probar los casos de error además de los casos de éxito de una función. Una función debe rechazar explícitamente la entrada incorrecta o debe tener documentación para explicar qué entrada se considera válida.

Si tiene una función que no está haciendo ninguna de esas cosas, es un error y debe tener una forma de registrar que existe. Crear una prueba unitaria que demuestre este problema es una forma de hacerlo. Presentar un ticket de error es otra opción.

El punto de las pruebas unitarias no es tener el 100% de éxito, el punto es encontrar y corregir errores en el código. No realizar pruebas es una manera fácil de tener el 100% de éxito, pero eso no es muy beneficioso para el proyecto.

muestreador
fuente
Woah ... "El objetivo de las pruebas unitarias no es tener el 100% de éxito", ¿estás diciendo que no todos tienen que pasar?
CaffGeek
2
@Chad: El punto es que es mejor tener pruebas que sabes que fallarán, pero están demostrando un problema real en lugar de no tener la prueba solo para que puedas tener la marca de verificación verde al final de la construcción / prueba nocturna.
Unholysampler
8
@unholysampler, nunca hay pruebas interrumpidas, a menos que estén CLARAMENTE marcadas como "debería" interrumpir (al estar en un proyecto diferente). De lo contrario, se convierten en ruido y no se sabe cuándo se ha roto una prueba que debería pasar. Derrota por completo el propósito de la integración continua y tener UnitTests
CaffGeek
2
@Chad: Creo que esto se está metiendo en la semántica de las definiciones. Según el OP, parecía que estaba hablando de crear una prueba válida que ejercitara un error. Sin embargo, el error es de baja prioridad y no es probable que se solucione de inmediato. Usted fue quien planteó la integración continua, lo que impone restricciones mucho más estrictas en el proceso automatizado.
Unholysampler
44
@unholysampler, CI, o no CI, el punto es que, cuando ejecutas las pruebas y estás acostumbrado a ver algunas luces rojas, te acostumbras. Entonces, cuando algo que era verde, se vuelve rojo ... ¿cómo lo sabes? Es una práctica horrible, y una de las razones por las que las pruebas no se aceptan en tantas organizaciones.
CaffGeek
1

Presente un error por cada falla y observe eso en el resultado de la prueba. Luego, si alguna vez actúas y corriges el error, tu prueba pasa y la eliminas del resultado de la prueba. Nunca ignores los problemas.

SnoopDougieDoug
fuente
-3

La forma en que veo que se hace TDD con la implementación de pruebas para un código inacabado es escribir primero las pruebas con el atributo [ExpectedException] o similar. Esto debería pasar inicialmente ya que el código incompleto no tendría ninguna lógica y escribiría un nuevo código de excepción (). Aunque pasar la excepción es incorrecto, al menos esto haría que las pruebas pasen inicialmente y que sean aptas para el registro. Podemos olvidar una prueba ignorada pero definitivamente podemos ordenar o completar el código incompleto. Cuando lo hagamos, automáticamente comenzará a fallar automáticamente la prueba correspondiente que esperaba una excpección y le alarmaría para que la arregle. Esto puede implicar una ligera alteración de la prueba para deshacerse de ExpectException y, en su lugar, hacer afirmaciones reales. ¿CI, Dev, evaluadores y clientes, todos contentos y en una situación en la que todos ganan?

usuario211764
fuente
1
Esto no responde a la pregunta. No está preguntando qué es TDD y por qué probar las excepciones esperadas.
Andy Wiesendanger