unit-testing - tutorial - pruebas unitarias php
Refactorización práctica usando pruebas unitarias (7)
Después de leer los primeros cuatro capítulos de Refactoring: mejorar el diseño del código existente , me embarqué en mi primera refactorización y casi de inmediato me tocó un obstáculo. Se deriva del requisito de que antes de comenzar la refactorización, debe realizar pruebas unitarias alrededor del código heredado. Eso le permite estar seguro de que su refactorización no cambió lo que hizo el código original (solo cómo lo hizo).
Así que mi primera pregunta es esta: ¿cómo puedo probar la unidad de un método en código heredado? ¿Cómo puedo poner una prueba unitaria alrededor de un método de 500 líneas (si tengo suerte) que no hace solo una tarea? Me parece que tendré que refactorizar mi código heredado solo para que pueda ser comprobado por la unidad.
¿Alguien tiene alguna experiencia refactorizando usando pruebas unitarias? Y, si es así, ¿tiene algún ejemplo práctico que pueda compartir conmigo?
Mi segunda pregunta es algo difícil de explicar. Aquí hay un ejemplo: quiero refactorizar un método heredado que rellena un objeto de un registro de base de datos. ¿No tendría que escribir una prueba unitaria que compare un objeto recuperado utilizando el método anterior, con un objeto recuperado utilizando mi método refactorizado? De lo contrario, ¿cómo sabría que mi método refactorizado produce los mismos resultados que el método anterior? Si eso es cierto, ¿cuánto tiempo dejo el viejo método obsoleto en el código fuente? ¿Simplemente lo golpeo después de probar algunos registros diferentes? O bien, ¿debo guardarlo por un tiempo en caso de encontrar un error en mi código refactorizado?
Por último, ya que un par de personas han preguntado ... el código heredado se escribió originalmente en VB6 y luego se transfirió a VB.NET con cambios mínimos de arquitectura.
Buen ejemplo de teoría que cumple con la realidad. Las pruebas unitarias están destinadas a probar una sola operación y muchos puristas de patrones insisten en la responsabilidad única , por lo que tenemos códigos limpios encantadores y pruebas que lo acompañan. Sin embargo, en el mundo real (desordenado), el código (especialmente el código heredado) hace muchas cosas y no tiene pruebas. Lo que esto necesita es una dosis de refactorización para limpiar el desastre.
Mi enfoque es construir pruebas, usando las herramientas Unit Test, que prueban muchas cosas en una sola prueba. En una prueba, puedo estar comprobando que la conexión de la base de datos está abierta, cambiando muchos datos y haciendo una comprobación de antes / después en la base de datos. Inevitablemente me encuentro escribiendo clases de ayuda para hacer la comprobación, y la mayoría de las veces esos ayudantes pueden agregarse a la base de código, ya que han encapsulado comportamiento / lógica / requisitos emergentes. No me refiero a que tengo una sola prueba enorme, lo que quiero decir es que las pruebas de Mnay están haciendo un trabajo que un purista llamaría una prueba de integración. ¿Todavía existe algo así? También me pareció útil crear una plantilla de prueba y luego crear muchas pruebas a partir de eso, para verificar las condiciones de contorno, el procesamiento complejo, etc.
Por cierto, ¿qué entorno de lenguaje estamos hablando? Algunos lenguajes se prestan a la refactorización mejor que otros.
Escriba pruebas en cualquier nivel del sistema que pueda (si puede), si eso significa ejecutar una base de datos, etc. entonces que así sea. Tendrá que escribir mucho más código para afirmar lo que el código está haciendo actualmente, ya que un método de 500 líneas + posiblemente tendrá mucho comportamiento envuelto en él. En cuanto a comparar lo viejo con lo nuevo, si escribes las pruebas contra el código anterior, pasan y cubren todo lo que hace, entonces cuando las ejecutas contra el nuevo código estás efectivamente comprobando lo viejo frente a lo nuevo. Hice esto para probar un disparador SQL complejo que quería refactorizar, fue un dolor y requirió tiempo, pero un mes después, cuando encontramos otro problema en esa área, valió la pena tener las pruebas allí en las que confiar.
Ese es realmente uno de los problemas clave de tratar de reinstalar el código heredado. ¿Eres capaz de dividir el dominio del problema en algo más granular? ¿Ese método de línea de más de 500 hace algo más que llamadas al sistema a archivos JAR / DLL / ensamblados JDK / Win32 / .NET Framework? Es decir, ¿hay llamadas de función más granulares dentro de ese límite de más de 500 líneas que podría probar una unidad?
Para obtener instrucciones sobre cómo refactorizar el código heredado, le recomendamos que lea el libro Working Effectively with Legacy Code . También hay una breve versión en PDF disponible aquí .
Según mi experiencia, escribiría pruebas no para métodos particulares en el código heredado, sino para la funcionalidad general que proporciona. Estos pueden o no pueden acercarse a los métodos existentes.
En mi experiencia, esta es la realidad cuando trabajo en código heredado. El libro (Working with Legacy ..) mencionado por Esko es un excelente trabajo que describe varios enfoques que pueden llevarte allí.
He visto problemas similares con mi propia prueba unitaria, que se ha convertido en una prueba de sistema / funcional. Lo más importante para desarrollar pruebas para código heredado o existente es definir el término "unidad". Puede ser incluso una unidad funcional como "leer desde la base de datos", etc. Identificar unidades funcionales clave y realizar pruebas que agreguen valor.
Como un aparte, hubo una conversación reciente entre Joel S. y Martin F. sobre TDD / pruebas unitarias. Mi opinión es que es importante definir la unidad y mantener el foco en ella. URLS: carta abierta , transcripción de Joel y podcast
El siguiente libro: El arte de las pruebas unitarias contiene un par de capítulos con algunas ideas interesantes sobre cómo lidiar con el código heredado en términos del desarrollo de pruebas unitarias.
Lo encontré bastante útil.