Agregar pruebas unitarias al código heredado [cerrado]

79

¿Alguna vez ha agregado pruebas unitarias, después del hecho, al código heredado? ¿Qué tan complicado era el código y qué tan difícil de copiar y burlarse de todo? ¿Valió la pena el resultado final?

BuckeyeSoftwareChico
fuente
4
Revisaré "Trabajar de manera efectiva con código heredado". ¡Con suerte, me dará algunos buenos consejos sobre cómo escribir envoltorios para todas estas dependencias estáticas!
BuckeyeSoftwareGuy

Respuestas:

57

Descubrí que la mejor manera es agregar gradualmente las pruebas unitarias, no solo saltar y decir que ahora probaremos la aplicación.

Entonces, si va a tocar el código, para corregir errores o refactorizar, primero escriba las pruebas unitarias. Para los errores, las pruebas unitarias ayudarán a demostrar dónde está el problema, ya que puede duplicarlo.

Si está refactorizando, querrá escribir pruebas unitarias, pero puede encontrar que la prueba es imposible de escribir, por lo que es posible que necesite encontrar un nivel alto, que llame a la función que se refactorizará, y probar unitaria esa parte. Luego, a medida que refactoriza la función ofensiva, escriba sus pruebas para asegurarse de que está funcionando como debería.

No hay una forma sencilla de hacer esto.

Esta pregunta puede ayudar con más sugerencias. ¿Cómo se introducen las pruebas unitarias en una base de código grande y heredada (C / C ++)?

James Black
fuente
8
+1 para agregar pruebas de forma incremental.
TrueWill
42

El libro de Michael Feathers "Trabajar eficazmente con el código heredado" es un libro completo que cubre este tema. Michael afirma que a menudo es demasiado difícil introducir pruebas para el código heredado porque no está estructurado para que se pueda probar. Lo que más saqué del libro fue un par de patrones llamados "Funciones de Sprout" y "Clases de Sprout". Una función de brote es aquella que encapsula el cambio que necesita hacer en el código. Luego, prueba unitariamente estas funciones únicamente. La clase sprout es la misma idea excepto que la nueva funcionalidad está contenida en una clase.

Phillip Ngan
fuente
10

Sí, y generalmente es doloroso. A menudo he tenido que escribir pruebas de integración.

El libro El arte de las pruebas unitarias tiene buenos consejos al respecto. También recomienda el libro Working Effectively with Legacy Code ; No he leído este último todavía, pero está en mi pila.

EDITAR: Pero sí, valió la pena incluso una cobertura mínima de código. Me dio confianza y una red de seguridad para refactorizar el código.

EDITAR: Leí Trabajar de manera efectiva con el código heredado, y es excelente.

TrueWill
fuente
4
+1 para "Trabajar eficazmente con el código heredado": lleno de excelentes consejos; de hecho, vale la pena leerlo incluso para entornos totalmente nuevos, solo como un gran recurso sobre la construcción de código para la prueba.
itowlson
1
+1 para la idea de reemplazar las pruebas unitarias con las pruebas de integración. Con la burla adecuada, los primeros son lo suficientemente buenos, con bastante frecuencia
DVK
7

Mire también el nuevo enfoque en el área de pruebas unitarias de código heredado: el proyecto Asis , está inspirado en el proyecto ApprovalTests y comparte sus conceptos clave.

Como se mencionó sobre el enfoque ApprovalTests en este artículo :

A menudo, tiene un gran proyecto de código heredado en el que no tiene pruebas en absoluto, pero debe cambiar el código para implementar una nueva característica o refactorizar. Lo interesante del código heredado es: ¡funciona! Funciona durante años, no importa cómo esté escrito. Y esta es una gran ventaja de ese código. Con las aprobaciones, con solo una prueba, puede obtener todos los resultados posibles (HTML, XML, JSON, SQL o cualquier resultado que pueda ser) y aprobar, porque ya sabe: ¡funciona! Una vez que haya completado dicha prueba y aprobado el resultado, estará mucho más seguro con una refactorización, ya que ahora "bloqueó" todo el comportamiento existente.

La herramienta Asis se trata exactamente de mantener el código heredado mediante la creación y ejecución de pruebas de caracterización automáticamente.

Para obtener más información, consulte

zavg
fuente
¿Cómo esto no tiene más votos a favor? Si el repositorio hace lo que dice que hace, esta debería ser la respuesta seleccionada.
lolololol ol
¿Se ocupa de los efectos secundarios en las funciones, por cierto? ¿Incluso es posible resolver este problema?
lolololol ol
5

Una alternativa a las pruebas unitarias, también introducida en Trabajar eficazmente con código heredado son las pruebas de caracterización . Tuve resultados interesantes con tales pruebas. Son más fáciles de configurar que las pruebas unitarias a medida que prueba desde un punto que lo que se puede probar (llamado costura). El inconveniente es que cuando falla una prueba, tiene menos pistas sobre la ubicación del problema, ya que el área bajo prueba puede ser mucho más grande que con las pruebas unitarias. El registro ayuda aquí.


Se puede utilizar un marco de prueba unitario como los de la familia xUnit para escribir pruebas de caracterización.

En tales pruebas, escritas después de los hechos, las afirmaciones verifican el comportamiento actual del código. A diferencia de las pruebas unitarias, no prueban que el código sea correcto, solo señalan (caracterizan) el comportamiento actual del código.

El proceso es similar al de TDD:

  • escribir una prueba para una parte del código
  • ejecutarlo - fallar
  • corregir la prueba a partir del comportamiento observado del código
  • ejecutarlo - pasar
  • repetir

Las pruebas fallarán si modifica el comportamiento externo del código. ¿Comportamiento externo del código? suena familiar ? Sí lo es, aquí estamos. Ahora puedes refactorizar el código.

Evidentemente, el riesgo depende de la cobertura de las pruebas de caracterización.

filántropo
fuente
5

Eche un vistazo a la biblioteca de utilidades de prueba unitaria de código abierto y gratuita, ApprovalTests . Si eres un desarrollador de .NET, el creador, Llewellyn Falco, ha realizado una serie de videos que muestran cómo usa ApprovalTests para mejorar las pruebas unitarias para código nuevo y heredado.

Lynn Langit
fuente
4

Si está planeando refactorizar el código heredado, entonces es imprescindible crear esas pruebas unitarias. No se preocupe por las burlas o las falsificaciones: preocúpese por probar las entradas y salidas del sistema para que sus cambios o esfuerzos de refactorización no rompan la funcionalidad actual.

No te mentiré, adaptar las pruebas unitarias al código heredado es difícil, pero vale la pena.

Andrew Hare
fuente
Comencé a crear pruebas unitarias para el código heredado en el que he estado trabajando. Sin embargo, me di cuenta de que he estado escribiendo pruebas de integración, no pruebas unitarias porque creo datos reales y los inserto en la base de datos. No veo una forma de crear simulacros puros y stubs para este código heredado porque no está estructurado para realizar pruebas en absoluto.
Vin Shahrdar
1

Hace algún tiempo estuve hablando sobre la idea de la pirámide de pruebas invertidas en el código heredado en XPDays http://xpdays.com.ua/archive/xp-days-ukraine-2012/materials/legacy-code/

Esta presentación debería responder a la pregunta de por qué a veces es tan importante comenzar con pruebas de integración / funcionales o incluso de aceptación de alto nivel cuando se trabaja con código heredado. Y luego, poco a poco, introduciendo las pruebas unitarias paso a paso. No hay ejemplos de código, lo siento, pero puede encontrar muchos de ellos en el libro de Michaels Feathers "Trabajar de manera efectiva con el código heredado".

También puede consultar Legacy Code Retreat http://www.jbrains.ca/legacy-code-retreat y buscar esa reunión en su área.

streser
fuente