Escritura de pruebas para el código existente

67

Supongamos que uno tiene un programa relativamente grande (digamos 900k SLOC en C #), todo comentado / documentado a fondo, bien organizado y funcionando bien. El código base completo fue escrito por un único desarrollador senior que ya no está en la empresa. Todo el código es verificable tal como está y IoC se usa en todas partes, excepto por alguna extraña razón por la que no escribieron ninguna prueba unitaria. Ahora, su empresa desea ramificar el código y desea que se agreguen pruebas unitarias para detectar cuándo los cambios rompen la funcionalidad principal.

  • ¿Es una buena idea agregar pruebas?
  • Si es así, ¿cómo se podría empezar con algo como esto?

EDIT

Bien, entonces no esperaba respuestas haciendo buenos argumentos para conclusiones opuestas. El problema puede estar fuera de mis manos de todos modos. También he leído las "preguntas duplicadas" y el consenso general es que "escribir exámenes es bueno" ... sí, pero no es muy útil en este caso en particular.

No creo que esté solo aquí al contemplar las pruebas de escritura para un sistema heredado. Mantendré las métricas sobre cuánto tiempo se gasta y cuántas veces las nuevas pruebas detectan problemas (y cuántas veces no lo hacen). Volveré y actualizaré esto en un año más o menos a partir de ahora con mis resultados.

CONCLUSION

Resulta que es básicamente imposible simplemente agregar una prueba de unidad al código existente con cualquier apariencia de ortodoxia. Una vez que el código está funcionando, es obvio que no puede hacer una luz roja / luz verde en sus pruebas, por lo general no está claro qué comportamientos son importantes para probar, no está claro por dónde empezar y, por supuesto, no está claro cuándo termina. Realmente, incluso hacer esta pregunta pierde el punto principal de escribir pruebas en primer lugar. En la mayoría de los casos, me resultó más fácil reescribir el código usando TDD que descifrar las funciones deseadas y agregar retroactivamente las pruebas unitarias. Cuando se soluciona un problema o se agrega una nueva característica, es una historia diferente, y creo que este es el momento de agregar pruebas unitarias (como se señala a continuación). Con el tiempo, la mayoría de los códigos se reescriben, a menudo antes de lo que esperabas. Al utilizar este enfoque, he podido agregar cobertura de prueba a una parte sorprendentemente grande del código base existente.

    
pregunta Paul 06.08.2013 - 17:27

7 respuestas

68

Si bien las pruebas son una buena idea, la intención era que el codificador original las construya, ya que estaba construyendo la aplicación para capturar su conocimiento de cómo se supone que funciona el código y qué se puede romper. que luego te habrían transferido.

Al adoptar este enfoque, existe una alta probabilidad de que esté escribiendo las pruebas que tienen menos probabilidades de interrumpir, y perderá la mayoría de los casos de borde que se hubieran descubierto al compilar la aplicación.

El problema es que la mayor parte del valor provendrá de esos 'errores' y situaciones menos obvias. Sin esas pruebas, el conjunto de pruebas pierde prácticamente toda su eficacia. Además, la compañía tendrá una falsa sensación de seguridad con respecto a su aplicación, ya que no será significativamente más resistente a la regresión.

Por lo general, la forma de manejar este tipo de base de código es escribir pruebas para el nuevo código y para refactorizar el código antiguo hasta que la base de código heredada sea completamente refacta.

También ver .

    
respondido por el FMJaguar 06.08.2013 - 18:02
36

Sí, agregar pruebas es definitivamente una buena idea.

Usted dice que está bien documentado y eso lo coloca en una buena posición. Intente crear pruebas utilizando esa documentación como guía, centrándose en partes del sistema que son críticas o están sujetas a cambios frecuentes.

Inicialmente, el tamaño total de la base de código probablemente parecerá abrumador en comparación con la pequeña cantidad de pruebas, pero no hay un enfoque de gran explosión, y hacer un comienzo en algún lugar es más importante que agonizar sobre El mejor enfoque será.

Recomendaría el libro de Michael Feathers, Trabajar de manera efectiva con el código heredado , para obtener consejos buenos y detallados.

    
respondido por el Danny Woods 06.08.2013 - 17:58
21

No todas las pruebas unitarias tienen el mismo beneficio. El beneficio de una prueba de unidad viene cuando falla. Cuanto menos probable es que falle, menos beneficioso es. Es más probable que los códigos nuevos o modificados recientemente contengan errores que los códigos raramente modificados que se han probado bien en producción. Por lo tanto, es más probable que las pruebas unitarias en códigos nuevos o recientemente modificados sean más beneficiosas.

No todas las pruebas unitarias tienen el mismo costo. Es mucho más fácil probar el código trivial que diseñó usted mismo hoy que el código complejo que alguien más diseñó hace mucho tiempo. Además, las pruebas durante el desarrollo generalmente ahorran tiempo de desarrollo. En el código heredado, los ahorros de costos ya no están disponibles.

En un mundo ideal, tendría todo el tiempo que necesita para hacer una prueba unitaria del código heredado, pero en el mundo real, en algún momento es lógico que los costos de agregar pruebas unitarias al código heredado superen los beneficios . El truco es identificar ese punto. Su control de versión puede ayudar al mostrarle el código más recientemente modificado y cambiado con mayor frecuencia, y puede comenzar poniéndolos a prueba de unidad. Además, cuando haga cambios en el futuro, ponga esos cambios y el código relacionado en la prueba de unidad.

Siguiendo ese método, finalmente tendrás una buena cobertura en las áreas más beneficiosas. Si en cambio pasa meses implementando pruebas unitarias antes de reanudar las actividades generadoras de ingresos, esa podría ser una decisión de mantenimiento de software deseable, pero es una decisión comercial pésima.

    
respondido por el Karl Bielefeldt 06.08.2013 - 20:03
8
  

¿Es una buena idea agregar pruebas?

Absolutamente, aunque me resulta un poco difícil creer que el código esté limpio, funcione bien y utilice técnicas modernas y simplemente no tenga pruebas unitarias. ¿Estás seguro de que no están sentados en una solución independiente?

De todos modos, si vas a extender / mantener el código, las verdaderas pruebas de unidad son invaluables para ese proceso.

  

Si es así, ¿cómo se podría empezar con algo como esto?

Un paso a la vez. Si no está familiarizado con las pruebas de unidad, aprenda un poco. Una vez que se sienta cómodo con los conceptos, elija una pequeña sección del código y escriba pruebas para ello. Luego lo siguiente, y lo siguiente. La cobertura del código puede ayudarlo a encontrar los lugares que ha perdido.

Probablemente sea mejor elegir cosas peligrosas / arriesgadas / vitales para probar primero, pero podría ser más efectivo probar algo sencillo para entrar primero en un surco, especialmente si usted / el equipo no está acostumbrado a la base de código y / o pruebas unitarias.

    
respondido por el Telastyn 06.08.2013 - 17:34
3

Sí, tener pruebas es una buena idea. Ayudarán a documentar las bases de código existentes según lo previsto y detectar cualquier comportamiento inesperado. Incluso si las pruebas inicialmente fallan, déjelas y luego refactorice el código más adelante para que pasen y se comporten según lo previsto.

Comience a escribir pruebas para clases más pequeñas (las que no tienen dependencias y son relativamente simples) y continúe con clases más grandes (las que tienen dependencias y son más complejas). Tomará mucho tiempo, pero sea paciente y persistente para que eventualmente pueda cubrir la base de código tanto como sea posible.

    
respondido por el Bernard 06.08.2013 - 17:33
3

Está bien, voy a dar la opinión contraria ...

Agregar pruebas a un sistema existente y funcional va a alterar ese sistema, a menos que sea así, todo el sistema está escrito con burlas en mente desde el principio. Lo dudo, aunque es bastante posible que tenga una buena separación de todos los componentes con límites fácilmente definibles en los que puede deslizar sus interfaces simuladas. Pero si no lo es, entonces tendrá que hacer cambios bastante significativos (relativamente hablando) que podrían romper las cosas. En el mejor de los casos, pasará una cantidad de tiempo escribiendo estas pruebas, tiempo que podría dedicarse mejor a escribir una carga de documentos de diseño detallados, documentos de análisis de impacto o documentos de configuración de soluciones. Después de todo, ese es el trabajo que su jefe quiere hacer más que pruebas de unidad. ¿No es así?

De todos modos, no agregaría ninguna prueba de unidad alguna.

Me concentraría en herramientas de prueba externas y automatizadas que le brindarán una cobertura razonable sin cambiar nada. Luego, cuando llegue a realizar modificaciones ... es cuando puede comenzar a agregar pruebas unitarias dentro de la base de código.

    
respondido por el gbjbaanb 13.08.2013 - 23:36
2

A menudo me he topado con esta situación, heredé una base de código grande sin una cobertura de prueba adecuada o sin cobertura, y ahora soy responsable de agregar funcionalidad, corregir errores, etc.

Mi consejo es que se asegure y pruebe lo que agrega, y si corrige errores o modifica los casos de uso en el código actual, las pruebas del autor entonces. Si tienes que tocar algo, escribe pruebas en ese punto.

Cuando esto se rompe es cuando el código existente no está bien estructurado para las pruebas unitarias, por lo que dedicas mucho tiempo a la refactorización para que puedas agregar pruebas para cambios menores.

    
respondido por el Casey 06.08.2013 - 20:28

Lea otras preguntas en las etiquetas