Uso de IoC para pruebas unitarias

97

¿Cómo se puede utilizar un contenedor de IoC para pruebas unitarias? ¿Es útil administrar simulacros en una gran solución (más de 50 proyectos) usando IoC? ¿Alguna experiencia? ¿Alguna biblioteca de C # que funcione bien para usarla en pruebas unitarias?

crauscher
fuente
7
@Mark Seemann sería demasiado humilde para señalarlo, pero si está interesado en esta pregunta, al menos debería estar al tanto de AutoFixture
Ruben Bartelink
1
Hay una buena charla sobre la relación entre DI y burlas en Vimeo por Miguel Castro: vimeo.com/68390510
GregC

Respuestas:

131

En términos generales, un contenedor DI no debería ser necesario para las pruebas unitarias porque las pruebas unitarias se tratan de separar responsabilidades.

Considere una clase que usa Constructor Injection

public MyClass(IMyDependency dep) { }

En toda su aplicación, puede ser que haya un gran gráfico de dependencia oculto detrás IMyDependency, pero en una prueba unitaria, lo reduce todo a un solo doble de prueba .

Puede usar simulacros dinámicos como Moq o RhinoMocks para generar el Test Double, pero no es necesario.

var dep = new Mock<IMyDependency>().Object;
var sut = new MyClass(dep);

En algunos casos, puede ser bueno tener un contenedor de simulación automática , pero no es necesario usar el mismo contenedor DI que usa la aplicación de producción.

Mark Seemann
fuente
13
de acuerdo ... a menos que un objetivo de prueba tenga un contenedor de IoC como dependencia, sus pruebas no deberían necesitarlas ... va a eliminar la mayor parte del gráfico de objetos cuando haga sus pruebas unitarias.
Anderson Imes
4
@Mark Seemann Esto tiene sentido ... Pero ¿qué pasa con las pruebas de integración? Es decir, jugué con las pruebas de UI y me enfrenté a una situación en la que tenía que compartir la raíz de la composición. ¿Algún comentario?
Arnis Lapsa
5
@Arnis L .: Para las pruebas de integración es menos importante. Puede optar por utilizar un contenedor DI para conectar los componentes, pero si es así, es probable que necesite una configuración diferente para el contenedor que en la aplicación completa, a menos que realice una prueba subcutánea o una prueba completa del sistema, en cuyo caso puede reutilizar la configuración de la aplicación del contenedor.
Mark Seemann
ref a la revista msdn Test Double: download.microsoft.com/download/3/A/7/…
M.Hassan
18

¿Cómo se puede utilizar un contenedor Ioc para pruebas unitarias?

IoC aplicará paradigmas de programación que facilitarán las pruebas unitarias de forma aislada (es decir, utilizando simulacros): uso de interfaces, no new (), no singletons ...

Pero usar el contenedor de IoC para las pruebas no es realmente un requisito, solo proporcionará algunas facilidades, por ejemplo, inyección de simulacros, pero puede hacerlo manualmente.

¿Es útil administrar simulacros en una gran solución (más de 50 proyectos) usando IoC?

No estoy seguro de a qué te refieres con administrar simulacros usando IoC. De todos modos, los contenedores de IoC generalmente pueden hacer más que inyectar simulacros cuando se trata de pruebas. Y si tiene un soporte IDE decente que hace posible la refactorización, ¿por qué no usarlo?

¿Cualquier experiencia?

Sí, en una solución enorme, necesita más que nunca una solución no propensa a errores y adversa a la refactorización (es decir, a través de un contenedor de IoC seguro de tipo o un buen soporte IDE).

Pascal Thivent
fuente
17

A menudo utilizo un contenedor de IoC en mis pruebas. Por supuesto, no son "pruebas unitarias" en el sentido puro. En mi opinión son más BDDish y facilitan la refactorización. Las pruebas están ahí para darle confianza para refactorizar. Las pruebas mal escritas pueden ser como verter cemento en su código.

Considera lo siguiente:

[TestFixture]
public class ImageGalleryFixture : ContainerWiredFixture
{
    [Test]
    public void Should_save_image()
    {
        container.ConfigureMockFor<IFileRepository>()
            .Setup(r => r.Create(It.IsAny<IFile>()))
            .Verifiable();

        AddToGallery(new RequestWithRealFile());

        container.VerifyMockFor<IFileRepository>();
    }

    private void AddToGallery(AddBusinessImage request)
    {
        container.Resolve<BusinessPublisher>().Consume(request);
    }
}

Hay varias cosas que suceden al agregar una imagen a la galería. Se cambia el tamaño de la imagen, se genera una miniatura y los archivos se almacenan en AmazonS3. Al usar un contenedor, puedo aislar más fácilmente solo el comportamiento que quiero probar, que en este caso es la parte persistente.

Una extensión de contenedor de burla automática es útil cuando se usa esta técnica: http://www.agileatwork.com/auto-mocking-unity-container-extension/

Mike Valenty
fuente
8
+1 para la frase "como verter cemento en su código". Empecé a usarlo todo el tiempo.
Andrew Shepherd
2

Usando contenedores con capacidad para resolver servicios no registrados / desconocidos como SimpleInjector , DryIoc (su mío) puede devolver simulacros para interfaces aún no implementadas.

Lo que significa que puede comenzar el desarrollo con la primera implementación simple y sus dependencias simuladas, y reemplazarlas con cosas reales a medida que avanza.

dadhi
fuente