Guillermo Valencia - Blog 
Este sitio web utiliza JavaScript. Por favor, habilítalo en tu navegador para que todo funcione correctamente.

Pruebas e Inversión de Control

Guillermo Valencia

Publicado el 02 de agosto de 2018

Tags: Patrones

Es habitual que tengamos la necesidad de integrar funcionalidad expuesta por componentes y servicios que están fuera del alcance del desarrollo que queremos probar. Las dependencias con sistemas externos afectan a la complejidad de la estrategia de pruebas, ya que es necesario contar con sustitutos de estos servicios externos durante el desarrollo.

Ejemplos típicos de estas dependencias son servicios Web, sistemas de envío de correo, fuentes u orígenes de datos, o simplemente, dispositivos hardware.

Estos sustitutos, muchas veces son exactamente iguales que el servicio original, pero en un entorno diferente al entorno de producción, es el caso de los entornos de desarrollo o de pruebas.

En otros casos es frecuente encontrarse con simuladores que exponen el mismo interfaz, pero realmente no realizan las mismas tareas que el sistema real, o las realizan contra un entorno controlado.

Para poder probar los escenarios más importantes, es necesario sincronizar el código de pruebas y el simulador de forma que desde la prueba se pueda saber a priori cómo será el comportamiento y así poder asegurar que el código a probar se ha ejecutado en las condiciones esperadas.
Simuladores

 

Este modelo de pruebas es muy conveniente para las pruebas de integración entre los diferentes módulos software de nuestra aplicación. Para ello es necesario que utilicemos interfaces que nos desacoplen de los sistemas externos, de manera que nuestros casos de uso del modelo de dominio trabajen directamente con las interfaces.

Para cada interfaz tendremos al menos dos implementaciones, una contra la fuente externa (o fuente real) y otra que la simule para nuestras pruebas.
Interfaces a implementaciones

 

¿Cómo elegiremos una u otra implementación dependiendo del entorno de ejecución?
Aquí nos surge un problema, y es que nuestra lógica de negocio debe ser capaz de instanciar tanto el objeto real como el objeto de pruebas, y decidir en cada caso cual debe utilizar.
Objetos reales o simulados

 

Y es aquí donde surge el término Inversión de control (IoC), que es el mecanismo de programación en el que el flujo de ejecución de un programa se invierte respecto a los métodos de programación tradicionales, en los que la interacción se expresa de forma imperativa haciendo llamadas a métodos o funciones. Tradicionalmente el programador especifica la secuencia de decisiones y procedimientos que pueden darse durante el ciclo de vida de un programa mediante llamadas a métodos, pero en su lugar, en la inversión de control se especifican respuestas deseadas a sucesos o solicitudes de datos concretas, dejando que algún tipo de entidad o arquitectura externa lleve a cabo las acciones de control que se requieran en el orden necesario y para el conjunto de sucesos que tengan que ocurrir.

Gracias a la orientación a objetos se puede definir un interfaz que cumplan tanto el objeto real como el objeto simulado, y hacer que el código a probar dependa tan sólo del interfaz que ambos implementan. Y se usará el patrón “Inversión de control” como mecanismo que permita elegir entre los dos tipos de objetos.

 

Dicho patrón puede ser implementado de diferentes formas. Las más comunes son:

  • Service Locator: en esta implementación, un servicio (Locator) es el encargado de saber qué instancia de un tipo concreto (interfaz) debe instanciar y retornar.
  • Service Locator

  • Dependency Injection: en esta implementación, existe un servicio (Builder) encargado de inyectar una implementación concreta de la interfaz al caso de uso. Esta implementación puede ser inyectada de varias maneras: por constructor, por propiedad o por parámetro.
  • Dependency Injection

Existen diferentes librerías que implementan el patrón “Inversión de Control”, como Microsoft Unity (https://msdn.microsoft.com/en-us/library/dn178463(v=pandp.30).aspx ) o StructureMap (http://structuremap.github.io/)