Pregunta

Estoy tratando de aprender a inyectar dependencias y me encontré con un problema al realizar pruebas unitarias de la aplicación.

Estoy escribiendo una aplicación de consola y el contenedor se crea e inicializa en Main(), está disponible como get-property en Program.Container, así que en cualquier lugar de mi aplicación puedo llamar Program.Container.Resolve<..>().

Tengo una clase ServiceValidator como esta:

public class ServiceValidator
{
    private readonly IConfiguration _configuration;
    private readonly IService _service;

    public ServiceValidator(IConfiguration configuration, IService service)
    {
        _configuration = configuration;
        _service = service;
    }

En otra clase uso

ServiceValidator serviceValidator = Program.Container.Resolve<ServiceValidator>();
serviceValidator.VerifyVersion();

es el llamado a Program.Container.Resolve eso me causa problemas en la prueba unitaria, ya que no ha sido configurado.

¿Es una mala práctica llamar a resolver en el contenedor?Podría crear la instancia de ServiceValidator en Main() y pasar el objeto, pero eso parece estúpido ya que causaría muchos parámetros para los objetos que simplemente se pasan al siguiente método.

Entonces supongo que es aceptable llamar a Resolve dentro de una clase, pero luego el contenedor debe configurarse para la prueba unitaria.¿Cómo debo hacer eso? ¿Debo mover el contenedor a otro lugar que no sea la clase Programa?¿Qué recomendarías?

Si es importante, estoy usando Unity y C#

Gracias :-)

¿Fue útil?

Solución

  

¿Es una mala práctica llamar a resolver en el contenedor? Podría crear la instancia de ServiceValidator en Main () y pasar el objeto, pero eso parece estúpido ya que causaría muchos parámetros para los objetos que se pasan al siguiente método.

Cuando usa la inyección de dependencia por completo, no necesitará pasar muchos parámetros a los objetos. El constructor de cada objeto debe tener como parámetros solo aquellas dependencias que usa directamente; no sabrá acerca de las dependencias transitivas de sus dependencias directas.

Entonces, si tiene una clase X que requiere un ServiceValidator, entonces la clase X tendrá un parámetro constructor de tipo ServiceValidator. Entonces, si alguna clase Y usa la clase X, entonces la clase Y tendrá un parámetro constructor de tipo X. Observe que Y no sabe nada sobre ServiceValidator, por lo que no necesita pasar el ServiceValidator de una clase a otro: el único lugar donde se usa es cuando se construye X, y eso a menudo lo hace un marco DI o en un solo lugar en una fábrica escrita a mano.

Algunos enlaces para más información:

Otros consejos

Por lo general, permito que las llamadas resuelvan dependencias del contenedor en lugares como main, aunque todavía trato de mantenerlas al mínimo. Lo que luego hago es configurar el contenedor en un método de inicialización de una clase de prueba. Lo he inicializado con implementaciones falsas para cualquier clase de prueba que necesite llamar al contenedor.

Las clases de prueba que no llaman a nada que requiera que se inicialice el contenedor pueden ignorarlo y no utilizar las falsificaciones. Por lo general, uso simulacros en esos casos.

También utilizo el Microsoft Service Locator para que la dependencia que estoy tomando está en algo de .NET Framework en lugar de en un contenedor específico. Esto me permite utilizar todo lo que quiera, incluso un contenedor casero.

Puede usar una clase estática como inicializador para su contenedor. Algo así como BootStrapper.cs estaría bien. Luego puede hacer referencia a los métodos de clase tanto en su código como en sus pruebas.

Bueno, lo que técnicamente estás haciendo es una ubicación de servicio en tu clase.

Recuerdo haber leído este artículo hace un tiempo:

http://martinfowler.com/articles/injection.html

Para mis clases, nunca trato de usar Resolve en ellas. Creo los objetos a través del contenedor cuando los necesito. Para las pruebas unitarias, utilizo algunas clases simuladas de biblioteca y código auxiliar.

El problema radica en el hecho de que está intentando probar el método Main. Este método es prácticamente imposible de realizar pruebas unitarias.

Yo diría que es mejor no hacer una prueba unitaria de su método Main porque:

  • El énfasis de las pruebas unitarias modernas se centra en el diseño
  • Debe minimizar la dependencia de la configuración en las pruebas unitarias. La configuración se puede probar con humo o pruebas de integración.
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top