Definitivamente una buena lista. Aquí hay algunos pensamientos al respecto:
Escriba primero la prueba y luego el código.
Estoy de acuerdo, en un alto nivel.Pero sería más específico: "Primero escribe una prueba y luego escribe con el código suficiente para pasar la prueba y repite". De lo contrario, me temo que las pruebas de mi unidad se parecerían más a las pruebas de integración o aceptación.
Clases de diseño usando la inyección de dependencia.
De acuerdo. Cuando un objeto crea sus propias dependencias, no tiene control sobre ellas. La inversión de Control/Dependency Injection le da ese control, lo que le permite aislar el objeto bajo prueba con mocks/stubs/etc. Así es como se prueban los objetos de forma aislada.
Separe el código de la IU de su comportamiento utilizando Model-View-Controller o Model-View-Presenter.
De acuerdo. Tenga en cuenta que incluso el presentador/controlador puede probarse usando DI/IoC, entregándole una vista y un modelo copiados/burlados. Consulte Presenter First TDD para obtener más información al respecto.
No escriba métodos o clases estáticos.
No estoy seguro Estoy de acuerdo con esto. Es posible probar un método/clase estático sin usar simulaciones. Entonces, quizás esta sea una de esas reglas específicas de Rhino Mock que mencionaste.
Programa de interfaces, no de clases.
Estoy de acuerdo, pero por un motivo ligeramente diferente. Las interfaces proporcionan una gran flexibilidad para el desarrollador de software, más allá del soporte para varios frameworks de objetos simulados. Por ejemplo, no es posible admitir DI correctamente sin interfaces.
Aislar las dependencias externas.
De acuerdo. Oculte dependencias externas detrás de su fachada o adaptador (según corresponda) con una interfaz. Esto le permitirá aislar su software de la dependencia externa, ya sea un servicio web, una cola, una base de datos u otra cosa. Esto es especialmente importante cuando su equipo no controla la dependencia (a.k.a. external).
Marque como virtuales los métodos que pretende simular.
Esa es una limitación de Rhino Mocks. En un entorno que prefiera trozos codificados a mano sobre un marco de objeto falso, eso no sería necesario.
Y, un par de nuevos puntos a considerar:
Use patrones de diseño creacional. Esto ayudará con DI, pero también le permite aislar ese código y probarlo independientemente de otra lógica.
Escribir pruebas usando Bill Wake's Arrange/Act/Assert technique. Esta técnica deja muy claro qué configuración es necesaria, qué se está probando realmente y qué se espera.
No tenga miedo de rodar sus propios simuladores. A menudo, descubrirá que el uso de frameworks de objetos falsos hace que sus pruebas sean increíblemente difíciles de leer. Al lanzar el suyo propio, tendrá control total sobre sus simulaciones/talones y podrá mantener sus pruebas legibles. (Refiérase al punto anterior.)
Evite la tentación de refactorizar la duplicación de las pruebas de su unidad en clases base abstractas o métodos de configuración/desmontaje. Al hacerlo, se oculta el código de configuración/limpieza del desarrollador que intenta realizar la prueba de la unidad. En este caso, la claridad de cada prueba individual es más importante que la refactorización de la duplicación.
Implementar la integración continua. Registre su código en cada "barra verde". Cree su software y ejecute su conjunto completo de pruebas unitarias en cada check-in. (Claro, esto no es una práctica de codificación, per se; pero es una herramienta increíble para mantener su software limpio y completamente integrado.)
Esta es una lista útil. Actualmente estamos usando NUnit y Rhino.Mocks, y es bueno deletrear estos criterios para los miembros del equipo que están menos familiarizados con este lado de las pruebas unitarias. –