¿Es más tolerable el código duplicado en las pruebas unitarias?


Arruiné varias pruebas unitarias hace algún tiempo cuando las realicé y las refactoricé para hacerlas más SECAS the la intención de cada prueba ya no estaba clara. Parece que hay un equilibrio entre la legibilidad de las pruebas y la mantenibilidad. Si dejo código duplicado en las pruebas unitarias, son más legibles, pero luego si cambio el SUT, tendré que rastrear y cambiar cada copia del código duplicado.

¿Está usted de acuerdo en que esta compensación existe? Si es así, ¿prefieres sus pruebas para ser legible, o mantenible?

Author: Daryl Spitzer, 2008-09-25

11 answers

El código duplicado es un olor en el código de prueba unitaria tanto como en otro código. Si ha duplicado el código en las pruebas, hace que sea más difícil refactorizar el código de implementación porque tiene un número desproporcionado de pruebas que actualizar. Las pruebas deben ayudarlo a refactorizar con confianza, en lugar de ser una gran carga que impida su trabajo en el código que se está probando.

Si la duplicación está en fixture set up, considere hacer más uso del método setUp o proporcionar más (o más flexible) Métodos de creación.

Si la duplicación está en el código manipulando el SUT, entonces pregúntese por qué múltiples pruebas llamadas "unit" están ejerciendo exactamente la misma funcionalidad.

Si la duplicación está en las aserciones, entonces tal vez necesite algunas Aserciones personalizadas. Por ejemplo, si varias pruebas tienen una cadena de aserciones como:

assertEqual('Joe', person.getFirstName())
assertEqual('Bloggs', person.getLastName())
assertEqual(23, person.getAge())

Entonces tal vez necesite un único método assertPersonEqual, para que pueda escribir assertPersonEqual(Person('Joe', 'Bloggs', 23), person). (O tal vez simplemente necesidad de sobrecargar el operador de igualdad en Person.)

Como usted menciona, es importante que el código de prueba sea legible. En particular, es importante que la intención de una prueba sea clara. Me parece que si muchas pruebas se ven casi iguales, (por ejemplo, tres cuartas partes de las líneas son iguales o prácticamente iguales) es difícil detectar y reconocer las diferencias significativas sin leerlas y compararlas cuidadosamente. Así que encuentro que la refactorización para eliminar la duplicación ayuda legibilidad, porque cada línea de cada método de prueba es directamente relevante para el propósito de la prueba. Eso es mucho más útil para el lector que una combinación aleatoria de líneas que son directamente relevantes y líneas que son simplemente repetitivas.

Dicho esto, a veces las pruebas están ejercitando situaciones complejas que son similares pero aún significativamente diferentes, y es difícil encontrar una buena manera de reducir la duplicación. Utilice el sentido común: si usted siente que las pruebas son legibles y hacer su intent clear, y te sientes cómodo con tal vez la necesidad de actualizar más de un número teóricamente mínimo de pruebas al refactorizar el código invocado por las pruebas, luego aceptar la imperfección y pasar a algo más productivo. Siempre puede volver y refactorizar las pruebas más tarde,cuando la inspiración golpea!

 55
Author: spiv,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-28 04:39:40

La legibilidad es más importante para las pruebas. Si una prueba falla, usted quiere que el problema sea obvio. El desarrollador no debería tener que vadear a través de una gran cantidad de código de prueba fuertemente factorizado para determinar exactamente lo que falló. No quieres que tu código de prueba se vuelva tan complejo que necesites escribir pruebas unitarias.

Sin embargo, eliminar la duplicación suele ser algo bueno, siempre y cuando no oculte nada, y eliminar la duplicación en sus pruebas puede conducir a una mejor API. Simplemente asegúrese de no ir más allá del punto de rendimientos decrecientes.

 145
Author: Kristopher Johnson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-04 00:11:21

El código de implementación y las pruebas son animales diferentes y las reglas de factorización se aplican de manera diferente a ellos.

El código o estructura duplicada es siempre un olor en el código de implementación. Cuando empiezas a tener repeticiones en la implementación, necesitas revisar tus abstracciones.

Por otro lado, el código de prueba debe mantener un nivel de duplicación. La duplicación en el código de prueba logra dos objetivos:

  • Mantener las pruebas disociadas. El acoplamiento de prueba excesivo puede dificultar el cambio una única prueba fallida que necesita actualización porque el contrato ha cambiado.
  • Mantener las pruebas significativas de forma aislada. Cuando una sola prueba está fallando, debe ser razonablemente sencillo averiguar exactamente lo que está probando.

Tiendo a ignorar la duplicación trivial en el código de prueba, siempre y cuando cada método de prueba se mantenga más corto que unas 20 líneas. Me gusta cuando el ritmo setup-run-verify es evidente en los métodos de prueba.

Cuando la duplicación se arrastra hacia arriba en la parte "verificar" de las pruebas, a menudo es beneficioso definir métodos de aserción personalizados. Por supuesto, esos métodos aún deben probar una relación claramente identificada que puede hacerse evidente en el nombre del método: assertPegFitsInHole - > bueno, assertPegIsGood - > malo.

Cuando los métodos de prueba crecen largos y repetitivos, a veces me resulta útil definir plantillas de prueba de relleno de espacios en blanco que tomen algunos parámetros. Luego, los métodos de prueba reales se reducen a una llamada al método de plantilla con los parámetros apropiados.

En cuanto a un lote de las cosas en programación y pruebas, no hay una respuesta clara. Necesitas desarrollar un sabor, y la mejor manera de hacerlo es cometer errores.

 36
Author: ddaa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-24 21:31:10

Puede reducir la repetición usando varios sabores diferentes de métodos de utilidad de prueba.

Soy más tolerante a la repetición en código de prueba que en código de producción, pero a veces me he sentido frustrado por ello. Cuando cambias el diseño de una clase y tienes que volver atrás y modificar 10 métodos de prueba diferentes que hacen los mismos pasos de configuración, es frustrante.

 7
Author: Don Kirkby,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-24 21:17:47

Estoy de acuerdo. La compensación existe pero es diferente en diferentes lugares.

Es más probable que refactorice el código duplicado para configurar el estado. Pero menos probable que refactorizar la parte de la prueba que realmente ejerce el código. Dicho esto, si el ejercicio del código siempre toma varias líneas de código, entonces podría pensar que es un olor y refactorizar el código real bajo prueba. Y eso mejorará la legibilidad y mantenibilidad tanto del código como de las pruebas.

 6
Author: stucampbell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-24 20:30:07

Jay Fields acuñó la frase "DSLs debe ser HÚMEDO, no SECO", donde HÚMEDO significa frases descriptivas y significativas. Creo que lo mismo se aplica a las pruebas, también. Obviamente, demasiada duplicación es mala. Pero eliminar la duplicación a toda costa es aún peor. Las pruebas deben actuar como especificaciones que revelen la intención. Si, por ejemplo, especifica la misma característica desde varios ángulos diferentes, entonces se espera una cierta cantidad de duplicación.

 4
Author: Jörg W Mittag,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-02 00:11:14

ME ENCANTA rspec por esto:

Tiene 2 cosas para ayudar -

  • Grupos de ejemplo compartidos para probar el comportamiento común.
    puede definir un conjunto de pruebas, luego 'incluir' ese conjunto en sus pruebas reales.

  • Contextos Anidados.
    esencialmente, puedes tener un método de 'configuración' y 'desmontaje' para un subconjunto específico de tus pruebas, no solo para cada una de la clase.

Cuanto antes. NET/Java/otros frameworks de prueba adopten estos métodos, mejor (o podría usar IronRuby o JRuby para escribir sus pruebas, que personalmente creo que es la mejor opción)

 3
Author: Orion Edwards,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-25 00:11:02

No creo que haya una relación entre código más duplicado y más legible. Creo que tu código de prueba debería ser tan bueno como tu otro código. El código que no se repite es más legible que el código duplicado cuando se hace bien.

 2
Author: Paco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-24 20:26:47

Idealmente, las pruebas unitarias no deberían cambiar mucho una vez que se escriben, por lo que me inclinaría hacia la legibilidad.

Que las pruebas unitarias sean lo más discretas posible también ayuda a mantener las pruebas enfocadas en la funcionalidad específica a la que se dirigen.

Dicho esto, tiendo a intentar reutilizar ciertas piezas de código que termino usando una y otra vez, como el código de configuración que es exactamente el mismo en un conjunto de pruebas.

 2
Author: 17 of 26,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-24 20:29:04

"los refactorizó para hacerlos más SECOS the la intención de cada prueba ya no estaba clara"

Parece que tuviste problemas haciendo la refactorización. Sólo estoy adivinando, pero si terminó menos claro, ¿no significa eso que todavía tiene más trabajo por hacer para que tenga pruebas razonablemente elegantes que son perfectamente claras?

Es por eso que las pruebas son una subclase de UnitTest so para que pueda diseñar buenos conjuntos de pruebas que sean correctos, fáciles de validar y claros.

En los viejos tiempos tenía herramientas de prueba que usaban diferentes lenguajes de programación. Era difícil (o imposible) diseñar pruebas agradables y fáciles de trabajar.

Tienes todo el poder de Python cualquier lenguaje que estés usando Python Python, Java, C# so así que usa bien ese lenguaje. Puede lograr un código de prueba atractivo que sea claro y no demasiado redundante. No hay compensación.

 2
Author: S.Lott,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-25 00:03:29

Creo que el código de prueba requiere un nivel similar de ingeniería que normalmente se aplicaría al código de producción. Ciertamente puede haber argumentos a favor de la legibilidad y estoy de acuerdo en que es importante.

En mi experiencia, sin embargo, encuentro que las pruebas bien factorizadas son más fáciles de leer y entender. Si hay 5 pruebas que cada una se ve igual, excepto por una variable que ha cambiado y la afirmación al final, puede ser muy difícil encontrar lo que esa única diferencia item es. Del mismo modo, si se factoriza de modo que solo la variable que está cambiando es visible y la afirmación, entonces es fácil averiguar lo que la prueba está haciendo inmediatamente.

Encontrar el nivel correcto de abstracción cuando las pruebas pueden ser difíciles y creo que vale la pena hacerlo.

 1
Author: Kevin London,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-02 22:16:56