Al contrario de las otras respuestas, es importante tener en cuenta que algunas formas de prueba pueden volverse frágiles cuando se refactoriza el sistema bajo prueba (SUT), si la prueba es una caja blanca.
Si estoy usando un marco burlón que verifica el orden de los métodos invocados en los simulacros (cuando el orden es irrelevante porque las llamadas están libres de efectos secundarios); entonces, si mi código está más limpio con esas llamadas a métodos en un orden diferente y refactorizo, entonces mi prueba se interrumpirá. En general, los simulacros pueden introducir fragilidad en las pruebas.
Si estoy verificando el estado interno de mi SUT al exponer a sus miembros privados o protegidos (podríamos usar "amigo" en Visual Basic, o escalar el nivel de acceso "interno" y usar "internalsvisibleto" en c #; en muchos idiomas OO, incluidos c # se podría usar una " subclase específica de prueba "), de repente, el estado interno de la clase será importante: puede que esté refactorizando la clase como un cuadro negro, pero las pruebas de cuadro blanco fallarán. Suponga que un solo campo se reutiliza para significar cosas diferentes (¡no es una buena práctica!) Cuando el SUT cambia de estado; si lo dividimos en dos campos, es posible que necesitemos reescribir pruebas rotas.
Las subclases específicas de prueba también se pueden usar para probar métodos protegidos, lo que puede significar que un refactorizador desde el punto de vista del código de producción es un cambio importante desde el punto de vista del código de prueba. Mover algunas líneas dentro o fuera de un método protegido puede no tener efectos secundarios de producción, pero interrumpa una prueba.
Si uso " ganchos de prueba " o cualquier otro código de compilación condicional o específico de prueba, puede ser difícil garantizar que las pruebas no se rompan debido a las dependencias frágiles de la lógica interna.
Por lo tanto, para evitar que las pruebas se acoplen a los detalles internos íntimos del SUT, puede ayudar a:
- Use trozos en lugar de simulacros, cuando sea posible. Para obtener más información, consulte el blog de Fabio Periera sobre pruebas tautológicas y mi blog sobre pruebas tautológicas .
- Si usa simulacros, evite verificar el orden de los métodos llamados, a menos que sea importante.
- Intente evitar verificar el estado interno de su SUT: use su API externa si es posible.
- Trate de evitar la lógica específica de la prueba en el código de producción.
- Trate de evitar el uso de subclases específicas de la prueba.
Todos los puntos anteriores son ejemplos de acoplamiento de caja blanca utilizados en las pruebas. Por lo tanto, para evitar por completo la refactorización de las pruebas de ruptura, utilice las pruebas de caja negra del SUT.
Descargo de responsabilidad: con el propósito de discutir la refactorización aquí, estoy usando la palabra un poco más ampliamente para incluir cambios en la implementación interna sin ningún efecto externo visible. Algunos puristas pueden estar en desacuerdo y referirse exclusivamente al libro Refactoring de Martin Fowler y Kent Beck, que describe las operaciones de refactorización atómica.
En la práctica, tendemos a dar pasos que no se rompen un poco más grandes que las operaciones atómicas descritas allí, y en particular los cambios que hacen que el código de producción se comporte de manera idéntica desde el exterior pueden no dejar pasar las pruebas. Pero creo que es justo incluir "algoritmo sustituto de otro algoritmo que tenga un comportamiento idéntico" como refactorizador, y creo que Fowler está de acuerdo. El propio Martin Fowler dice que la refactorización puede romper las pruebas:
Cuando escribe una prueba simulada, está probando las llamadas salientes del SUT para asegurarse de que hable correctamente con sus proveedores. Una prueba clásica solo se preocupa por el estado final, no por cómo se derivó ese estado. Las pruebas simuladas están, por lo tanto, más acopladas a la implementación de un método. Cambiar la naturaleza de las llamadas a los colaboradores generalmente hace que se rompa una prueba simulada.
[...]
El acoplamiento a la implementación también interfiere con la refactorización, ya que es mucho más probable que los cambios de implementación rompan las pruebas que con las pruebas clásicas.
Fowler: los simulacros no son trozos