Uno de los proyectos en los que trabajé fue fuertemente probado en unidades; tuvimos más de 1000 pruebas unitarias para aproximadamente 20 clases. Hubo un poco más de código de prueba que código de producción. Las pruebas unitarias detectaron innumerables errores introducidos durante las operaciones de refactorización; definitivamente hicieron que sea fácil y seguro realizar cambios, ampliar la funcionalidad, etc. El código publicado tenía una tasa de errores muy baja.
Para animarnos a escribir las pruebas unitarias, elegimos específicamente mantenerlas 'rápidas y sucias' - probamos una prueba cuando produjimos el código del proyecto, y las pruebas fueron aburridas y 'código no real', así que tan pronto como escribimos uno que ejerció la funcionalidad del código de producción, terminamos y continuamos. El único criterio para el código de prueba fue que ejerció completamente la API del código de producción.
Lo que aprendimos de la manera difícil es que este enfoque no escala. A medida que el código evolucionó, vimos la necesidad de cambiar el patrón de comunicación entre nuestros objetos, ¡y de repente tuve 600 pruebas unitarias fallidas! Reparar esto me tomó varios días. Este nivel de rotura de prueba ocurrió dos o tres veces con refactorizaciones de arquitectura más importantes. En cada caso, no creo que podamos razonablemente haber previsto la evolución del código que se requería de antemano.
La moraleja de la historia para mí fue esta: código de prueba de unidad debe ser tan limpio como el código de producción. Simplemente no puede salirse con la tarea de cortar y pegar en pruebas unitarias. Debe aplicar una refactorización razonable y desacoplar las pruebas del código de producción cuando sea posible mediante el uso de objetos proxy.
Por supuesto, todo esto agrega complejidad y costo a las pruebas de su unidad (¡y puede introducir errores en sus pruebas!), Por lo que es un buen equilibrio. Pero sí creo que el concepto de "pruebas unitarias", tomado en forma aislada, no es la victoria clara e inequívoca que a menudo se supone que es. Mi experiencia es que las pruebas unitarias, como todo lo demás en programación, requieren cuidado y no son una metodología que se pueda aplicar a ciegas. Por lo tanto, es sorprendente para mí que no haya visto más discusión sobre este tema en foros como este y en la literatura.
¿No es esto más bien un mal diseño de prueba unitaria? – txwikinger
@txwikinger, no veo cómo podría ser un mal diseño. Si realiza pruebas de unidad de nivel de API y la API cambia, dará como resultado los cambios correspondientes en las pruebas de unidad. – JaredPar
Bien ... las pruebas unitarias contrastan con las especificaciones. Si eso cambia, la prueba de la unidad también debe cambiar. Probablemente creo que es bueno de esa manera, ya que los cambios de la API probablemente causen roturas en otro lado. – txwikinger