Si el código de prueba de la unidad "huele" ¿realmente importa?

52

Por lo general, solo hago mis pruebas unitarias usando copiar y pegar y todo tipo de otras malas prácticas. Las pruebas unitarias por lo general terminan luciendo bastante feas, están llenas de "olor a código", pero ¿esto realmente importa? Siempre me digo que siempre que el código "real" sea "bueno" es lo único que importa. Además, las pruebas unitarias generalmente requieren varios "hacks malolientes", como funciones de aplastamiento.

¿Qué tan preocupado debería estar por pruebas de unidad mal diseñadas ("malolientes")?

    
pregunta Buttons840 18.05.2011 - 21:41

12 respuestas

72

¿Son importantes los olores de la prueba unitaria? Sí definitivamente. Sin embargo, son diferentes de los olores de código porque las pruebas unitarias tienen un propósito diferente y tienen un conjunto diferente de tensiones que informan su diseño. Muchos olores en el código no se aplican a las pruebas. Dada mi mentalidad de TDD, realmente diría que los olores de las pruebas unitarias son más importantes que los olores de código porque el código está ahí para satisfacer las pruebas.

Aquí hay algunos olores comunes de prueba de unidad:

  • Fragilidad : ¿tus pruebas fallan a menudo e inesperadamente incluso por cambios de código aparentemente triviales o no relacionados?
  • Fugas de estado : ¿las pruebas fallan de manera diferente según, por ejemplo, en qué orden se ejecutan?
  • Configuración / Bloqueo de arranque : ¿Son los bloques de configuración / desmontaje largos y cada vez más largos? ¿Realizan algún tipo de lógica de negocios?
  • Tiempo de ejecución lento : ¿las pruebas tardan mucho en ejecutarse? ¿Alguna de sus pruebas de unidad individual demora más de una décima de segundo en ejecutarse? (Sí, en serio, una décima de segundo).
  • Fricción : ¿Las pruebas existentes dificultan la escritura de nuevas pruebas? ¿Se encuentra luchando contra las fallas de las pruebas a menudo mientras refactoriza?

La importancia de los olores es que son indicadores útiles de diseño u otras cuestiones más fundamentales, es decir, "donde hay humo, hay fuego". No solo busque olores de prueba, busque su causa subyacente también.

Por otro lado, aquí hay algunas buenas prácticas para las pruebas unitarias:

  • Comentarios rápidos y enfocados : sus pruebas deben aislar la falla rápidamente y brindarle información útil sobre su causa.
  • Minimizar la distancia del código de prueba : debe haber una ruta clara y corta entre la prueba y el código que la implementa. Las largas distancias crean bucles de retroalimentación innecesariamente largos.
  • Pruebe una cosa a la vez : las pruebas unitarias solo deben probar una cosa. Si necesita probar otra cosa, escriba otra prueba.
  • Un error es una prueba que olvidó escribir : ¿Qué puede aprender de esta falla para escribir mejores y más completas pruebas en el futuro?
respondido por el Rein Henrichs 18.05.2011 - 22:27
67

estar preocupado. Escribes pruebas unitarias para probar que tu código actúa de la manera que esperas. Permiten que usted refactorice rápidamente con confianza. Si sus pruebas son frágiles, difíciles de entender o difíciles de mantener, ignorará las pruebas fallidas o las desactivará a medida que evolucione su base de código, lo que anulará muchos de los beneficios de escribir pruebas en primer lugar.

    
respondido por el jayraynet 18.05.2011 - 21:48
19

Acabo de terminar de leer The Art of Unit Testing hace un par de días. El autor aboga por poner tanto cuidado en sus pruebas de unidad como usted hace su código de producción.

He experimentado de primera mano pruebas mal escritas y que no se pueden mantener. He escrito algunos de los míos. Está virtualmente garantizado que si una prueba es un dolor en el culo para mantener, no se mantendrá. Una vez que las pruebas no están sincronizadas con el código bajo prueba, se han convertido en nidos de mentiras y engaños. El objetivo principal de las pruebas unitarias es infundir confianza en que no hemos roto nada (es decir, crean confianza). Si no se puede confiar en las pruebas, son peores que inútiles.

    
respondido por el Joshua Smith 18.05.2011 - 22:05
7

Siempre que su prueba de unidad realmente pruebe su código en "la mayoría" de los casos. (Dijo que la mayoría a propósito, ya que a veces es difícil encontrar todos los resultados posibles). Creo que el código "maloliente" es su preferencia personal. Siempre escribo el código de una manera que puedo leerlo y entenderlo en unos pocos segundos, en lugar de hojear la basura y tratar de entender qué es qué. Especialmente cuando vuelves a ella después de un tiempo considerable.

Línea inferior - su prueba, se supone que es fácil. No debes confundirte con el código "maloliente".

    
respondido por el Luke 18.05.2011 - 21:45
6

Definitivamente. Algunas personas dicen que "cualquier prueba es mejor que ninguna prueba". Estoy totalmente en desacuerdo: las pruebas mal escritas atascan tu tiempo de desarrollo y terminas perdiendo días reparando pruebas "rotas" porque no eran buenas pruebas de unidad en primer lugar. Para mí en este momento, las dos cosas en las que me estoy enfocando para que mis exámenes sean valiosos, en lugar de una carga, son:

Capacidad de mantenimiento

Debería probar el resultado ( qué sucede), no el método ( cómo sucede). Su configuración para la prueba debe ser lo más desconectada posible de la implementación: solo configure los resultados de las llamadas de servicio, etc. que sean absolutamente necesarios.

  • Use un marco de burla para asegurarse de que sus pruebas no dependan de nada externo
  • Favorece los stubs sobre los simulacros (si tu marco los distingue entre ellos) siempre que sea posible
  • No hay lógica en las pruebas! Los ifs, switches, for-eaches, casos, try-catches, etc. son todos grandes "no-nos", ya que pueden introducir errores en el propio código de prueba.

Legibilidad

Está bien permitir un poco más de repetición en tus pruebas, lo que normalmente no permitirías en tu código de producción, si las hace más legibles. Solo equilibra esto con las cosas de mantenimiento arriba. ¡Sea explícito en lo que está haciendo la prueba!

  • Intente mantener un estilo de "organizar, actuar, afirmar" para sus pruebas. Esto separa su configuración y las expectativas del escenario, de la acción que se realiza y el resultado que se afirma.
  • Mantenga una aseveración lógica por prueba (si el nombre de su prueba tiene "y" en ella, es posible que tenga que dividirla en varias pruebas)

En conclusión, deberías estar muy preocupado con las pruebas "malolientes": pueden acabar siendo una pérdida de tiempo, sin ningún valor.

Has dicho:

  

La prueba de la unidad por lo general requiere varios "hacks malolientes", como funciones de aplastamiento.

Parece que definitivamente podrías hacerlo leyendo algunas técnicas de Pruebas unitarias, como el uso de un marco de Mocking, para que tu vida sea mucho más fácil. Recomiendo encarecidamente The Art of Unit Testing , que cubre lo anterior y mucho más. Lo encontré esclarecedor después de haber luchado con pruebas mal escritas, que no se pueden mantener, "malolientes" durante mucho tiempo. ¡Es una de las mejores inversiones de tiempo que he hecho este año!

    
respondido por el mjhilton 19.05.2011 - 02:42
5

Dos preguntas para ti:

  • ¿Está absolutamente seguro de que está probando lo que piensa que está probando?
  • Si alguien más mira la prueba de la unidad, ¿podrán averiguar qué se supone que hace el código ?

Hay formas de lidiar con tareas repetitivas en sus pruebas unitarias que son más comúnmente el código de instalación y desmontaje. Esencialmente, tiene un método de configuración de prueba y un método de eliminación de prueba; todos los marcos de prueba de unidad tienen soporte para esto.

Las pruebas unitarias deben ser pequeñas y fáciles de entender. Si no lo son y la prueba falla, ¿cómo va a solucionar el problema en un período de tiempo razonablemente corto? Haz que te resulte fácil durante un par de meses cuando tengas que volver al código.

    
respondido por el Berin Loritsch 18.05.2011 - 21:49
5

Cuando la basura comienza a oler, es hora de sacarla. Su código de prueba debe ser tan limpio como su código de producción. ¿Se lo mostrarías a tu madre?

    
respondido por el Bill Leeper 18.05.2011 - 22:54
3

Además de las otras respuestas aquí.

El código de baja calidad en las pruebas unitarias no se limita a su conjunto de pruebas unitarias.

Uno de los roles que ocupa Unit Testing es la documentación.

El conjunto de pruebas de unidad es uno de los lugares donde se busca para averiguar cómo se debe usar una API.

Es poco probable que las personas que llaman de su API copien partes de su conjunto de pruebas de unidad, lo que lleva a que su código de conjunto de pruebas incorrecto infecte el código en vivo en otra parte.

    
respondido por el Paul Butcher 19.05.2011 - 11:54
3

Casi no presenté mi respuesta, ya que me tomó un tiempo descubrir cómo abordar esto como una pregunta legítima.

Las razones por las que los programadores se involucran en las "mejores prácticas" no son por razones estéticas o porque quieren un código "perfecto". Es porque les ahorra tiempo.

  • Ahorra tiempo porque un buen código es más fácil de leer y entender.
  • Ahorra tiempo porque cuando necesitas encontrar una solución a un error, es más fácil y rápido de localizar.
  • Ahorra tiempo porque cuando quieres extender el código es más fácil y rápido hacerlo.

Entonces, la pregunta que hace su pregunta (desde mi punto de vista) es ¿Debo ahorrarme tiempo o escribir un código que me haga perder el tiempo?

A esa pregunta solo puedo decirte, ¿qué tan importante es tu tiempo?

Para tu información: el aplastamiento, la burla y el parche de los monos tienen usos legítimos. Solo "huelen" cuando su uso no es apropiado.

    
respondido por el dietbuddha 18.05.2011 - 22:26
2

Intento específicamente NO hacer que mis pruebas de unidad sean también robos. He visto pruebas de unidad que comienzan a hacer el manejo de errores en nombre de ser robusto. Lo que terminas con son pruebas que se tragan los errores que intentan atrapar. Las pruebas unitarias también tienen que hacer algunas cosas extrañas con bastante frecuencia para que las cosas funcionen. Piensa en la idea completa de que los usuarios privados utilicen la reflexión ... si viera un montón de ellos en el código de producción, me preocuparía 9 de cada 10. Creo que debería dedicarse más tiempo a pensar en lo que se está probando. , en lugar de codificar la limpieza. Las pruebas deberán cambiarse con bastante frecuencia de todos modos si haces una refactorización importante, así que, ¿por qué no hackearlas juntas, tener un poco menos de sentimientos de propiedad y estar más motivada para volver a escribirlas o volver a trabajar cuando llegue el momento?

    
respondido por el Morgan Herlocker 18.05.2011 - 22:49
2

Si opta por una cobertura pesada y de bajo nivel, pasará tanto tiempo o más en el código de prueba como en el código del producto cuando realice modificaciones serias.

Dependiendo de la complejidad de la configuración de prueba, el código puede ser más complejo. (httpcontext.current vs. el horrible monstruo de intentar construir uno falso con precisión, por ejemplo)

A menos que su producto sea algo en el que rara vez realice un cambio importante en las interfaces existentes y que las entradas de nivel de unidad sean muy fáciles de configurar, me sentiría por lo menos preocupado por la comprensión de las pruebas como el producto real.

    
respondido por el Bill 18.05.2011 - 23:23
0

Los olores de código son solo un problema en el código que hace que sea necesario cambiarlos o entenderlos en algún momento posterior.

Así que creo que deberías corregir los olores de código cuando tienes que "acercarte" a la prueba de la unidad dada, pero no antes.

    
respondido por el Ian 23.06.2011 - 15:37

Lea otras preguntas en las etiquetas