Estoy trabajando para hacer que mis clases sean comprobables por unidad, usando la inyección de dependencia. Pero algunas de estas clases tienen muchos clientes, y aún no estoy listo para refactorizarlos para comenzar a pasar las dependencias. Entonces estoy tratando de hacerlo gradualmente; manteniendo las dependencias predeterminadas por ahora, pero permitiendo que se anulen para la prueba.
Un enfoque que estoy planteando es simplemente mover todas las llamadas "nuevas" a sus propios métodos, por ejemplo:
public MyObject createMyObject(args) {
return new MyObject(args);
}
Luego, en mis pruebas unitarias, puedo subclasificar esta clase y anular las funciones de creación, para que creen objetos falsos.
¿Es este un buen enfoque? ¿Hay alguna desventaja?
En términos más generales, ¿está bien tener dependencias codificadas, siempre que pueda reemplazarlas para realizar pruebas? Sé que el enfoque preferido es exigirlos explícitamente en el constructor, y me gustaría llegar allí eventualmente. Pero me pregunto si este es un buen primer paso.
Una desventaja que se me acaba de ocurrir: si tiene subclases reales que necesita probar, no puede reutilizar la subclase de prueba que escribió para la clase principal. Tendrá que crear una subclase de prueba para cada subclase real, y tendrá que anular las mismas funciones de creación.
Respuestas:
Este es un buen enfoque para comenzar. Tenga en cuenta que lo más importante es cubrir su código existente con pruebas unitarias; Una vez que tenga las pruebas, puede refactorizar más libremente para mejorar aún más su diseño.
Entonces, el punto inicial no es hacer que el diseño sea elegante y brillante, solo hacer que la unidad de código sea verificable con los cambios menos riesgosos . Sin pruebas unitarias, debe ser más conservador y cauteloso para evitar descifrar su código. Estos cambios iniciales pueden incluso hacer que el código se vea más torpe o feo en algunos casos, pero si te permiten escribir las primeras pruebas unitarias, eventualmente podrás refactorizar hacia el diseño ideal que tienes en mente.
El trabajo fundamental para leer sobre este tema es trabajar eficazmente con código heredado . Describe el truco que muestra arriba y muchos, muchos más, usando varios idiomas.
fuente
La gente de Guice recomienda usar
para todas las propiedades en lugar de simplemente agregar @Inject a su definición. Esto le permitirá tratarlos como beans normales, lo que puede hacer
new
al probar (y configurar las propiedades manualmente) y @Inject en producción.fuente
Cuando me enfrente con este tipo de problema, identificaré cada dependencia de mi clase a prueba y crearé un constructor protegido que me permitirá pasarlos. Esto es efectivamente lo mismo que crear un setter para cada uno, pero prefiero declarando dependencias en mis constructores para que no me olvide de crear instancias en el futuro.
Entonces, mi nueva clase de unidad de prueba tendrá 2 constructores:
fuente
Es posible que desee considerar la expresión "getter crea" hasta que pueda usar la dependencia inyectada.
Por ejemplo,
Esto le permitirá refactorizar internamente para que pueda hacer referencia a su myObject a través del captador. Nunca tienes que llamar
new
. En el futuro, cuando todos los clientes estén configurados para permitir la inyección de dependencias, todo lo que tiene que hacer es eliminar el código de creación en un lugar: el captador. El setter le permitirá inyectar objetos simulados según sea necesario.El código anterior es solo un ejemplo y expone directamente el estado interno. Debe considerar cuidadosamente si este enfoque es apropiado para su base de código.
También le recomendaría que lea " Trabajar eficazmente con código heredado ", que contiene una gran cantidad de consejos útiles para tener éxito en una refactorización importante.
fuente