¿Debo refactorizar las pruebas de mi unidad cuando extraigo una clase del Sistema bajo prueba?

13

Escribí esta clase que hace algunas cosas (tal vez esto es una violación del Principio de Responsabilidad Única). Ahora me doy cuenta de que otra parte del proyecto necesita una parte de esa lógica y la forma en que la expondré es extraer una clase de mi Sistema bajo prueba original.

Anticipo poder hacer esto sin tener que cambiar ningún código de prueba, pero cuando termine, podría argumentar que la prueba ya no es una prueba unitaria . Probará la clase original y la clase que he extraído. En otras palabras, tendré un caso de prueba, pero dos sistemas bajo prueba.

¿Se supone que debo refactorizar mi código de prueba una vez que haya terminado? IE: ¿Crear un ExtractedClassTest y mover todas las pruebas relevantes de OriginalClassTest a él? Parece que podría ser un poco arriesgado: puedo perder algo de cobertura en el proceso, puede que no sea tan simple como mover una prueba y terminaría reescribiendo un código de prueba que sé que solía funcionar, pero que ya no funciona, etc.

Por otro lado, si dejo el OriginalClassTest tal como está, puedo ver que se trata de un problema de mantenimiento de prueba. Será un poco confuso encontrar dónde están las pruebas de ExtractedClass. Su primera impresión será que no existe. Con el tiempo, con muchas refactorizaciones de código de producción, esto podría convertirse en un problema grave.

Soy nuevo en TDD, así que me gustaría el consejo de un experto. ¡Gracias!

Daniel Kaplan
fuente

Respuestas:

7

Después de ver esta increíble charla "Ian Cooper: TDD, ¿dónde salió todo mal?", Voy a estar en desacuerdo con @pdr. Creo que solo debes conservar las pruebas originales. Su capacidad de refactorizar su sistema bajo prueba sin romper, escribir o cambiar ninguna prueba es, en primer lugar, el propósito de escribir pruebas.

Si tuviera que probar la clase extraída, estaría probando la implementación en lugar del comportamiento. Como resultado, mi código sería más difícil de refactorizar en el futuro: estas nuevas pruebas probablemente fallarían incluso si el comportamiento aún funcionara.

Daniel Kaplan
fuente
6

Para la duración del desarrollo, tenga ambos. Mantenga las pruebas anteriores como garantía de que no ha roto nada, escriba nuevas pruebas (desde cero) para ayudarlo a diseñar las clases como deberían ser.

Al final, revisa y elimina todo lo que haya desaparecido en las pruebas anteriores. Tenga cuidado en este análisis; no elimines algo porque crees que debería estar difunto. Demuéstrese a usted mismo (o a otra persona, o un pato de goma) por qué ya no es necesario. Rompa la prueba y asegúrese de que otra prueba rompa con ella.

Cualquier cosa que quede en las pruebas anteriores debe tomarse caso por caso, pero sobre todo debe reescribirse en la nueva estructura.

Porque tienes razón, no quieres quedarte con una pesadilla de mantenimiento. Pero no desea menos cobertura de ruta que la que tenía antes.

pdr
fuente
1
Acabo de hacer esto y debo decir que es bastante desmotivador. A pesar de que mis cambios fueron directos, me tomó cerca de 2 horas asegurarme de que refactorice mis pruebas correctamente y aún tenga la misma cobertura. Se hizo evidente que debía agregar algunas pruebas adicionales a la nueva prueba solo para asegurarme de que estaba revisando las cosas. Siento que hubiera sido más eficiente extraer la clase y dejar dos sistemas bajo prueba. ¿Esta cantidad de trabajo sugiere que escribí mal las pruebas?
Daniel Kaplan
1
@tieTYT: Es difícil responder eso sin estar sentado mirándote. A veces, TDD parece más trabajo de lo que vale. Otras veces, te recuerdas por qué te molestaste. Y otras veces, eres tú quien lo hace más difícil. Aprender a notar la diferencia es una gran parte de ser bueno en TDD.
pdr
¿Crees que es una posibilidad que en este caso no debería haber refactorizado mis pruebas o crees que es poco probable?
Daniel Kaplan
1
@tieTYT: poco probable, sí. Imposible no.
pdr