Probar un objeto que instancia a sus propios colaboradores

Esta semana pasada he tenido el siguiente problema:

Queremos probar una clase (Flow) que implementa un flujo de llamadas a otros objetos (Tasks) que representan tareas.

En principio, parece un enunciado bastante simple, pero la dificultad radica en que no es posible sustituir las tareas por dobles (mocks) porque son instanciadas dentro del propio flujo. ¿Qué estrategia de prueba podemos seguir entonces?

Inicialmente lo hemos resuelto teniendo una TaskFactory que inyectamos al flujo, de tal modo que podamos hacer un doble de ésta (con EasyMock).

Pero este fin de semana, con algo más de tranquilidad, he estado reflexionando y me he dado cuenta de que realmente no estábamos siguiendo una buena estrategia, puesto que habíamos hecho un diseño contraintuitivo simplemente porque no éramos capaces de hacer pruebas unitarias del objeto Flow. Es más, en mi opinión, lo que estábamos probando era que habíamos escrito el código que estaba ya escrito… es decir, no estábamos realmente probando ni el resultado final ni las colaboraciones con objetos externos al propio SUT (System Under Test, que dice la bibliografía más reconocida). Estábamos probando que se ejecutaban las diferentes líneas del algoritmo. Mmmm… me parece que eso no es una prueba unitaria…

Pues bien, dándole vueltas al tema he llegado a la conclusión de que:

  • las tareas son parte del flujo, e.d., son parte del SUT
  • nuestra intención era probar las salidas indirectas del flujo
  • deberíamos comprobar las llamadas a sistemas externos que puedan hacer las tareas, e.d. necesitamos puntos de observación para esas llamadas
  • también puedo probar es el estado final del SUT, lo cuál me ha dado la pista de que puedo pasar un contexto (FlowContext) al flujo, de tal modo que cada una de las tareas pueda modificarlo y yo comprobar al final de cada prueba el resultado final (esto me viene bien, por cierto, para otros requisitos que tengo más adelante…)
Tagged: