es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Cómo simulo la dependencia de fábrica Func para devolver diferentes objetos utilizando AutoMock?

Estoy intentando escribir una prueba para una clase que depende del constructor en una Func<T>. Para que la función de prueba se complete con éxito, necesita crear varios objetos separados de tipo T.

Cuando se ejecuta en producción, AutoFac genera un nuevo T cada vez que se llama a factory(). Sin embargo, al escribir una prueba usando AutoMock, devuelve el mismo objeto cuando se llama de nuevo.

El caso de prueba a continuación muestra la diferencia en el comportamiento al usar AutoFac y AutoMock. Esperaría que ambos pasen, pero el de AutoMock falla.

public class TestClass
{
    private readonly Func<TestDep> factory;

    public TestClass(Func<TestDep> factory)
    {
        this.factory = factory;
    }

    public TestDep Get()
    {
        return factory();
    }
}

public class TestDep
{}

[TestMethod()]
public void TestIt()
{
    using var autoMock = AutoMock.GetStrict();

    var testClass = autoMock.Create<TestClass>();

    var obj1 = testClass.Get();
    var obj2 = testClass.Get();

    Assert.AreNotEqual(obj1, obj2);
}

[TestMethod()]
public void TestIt2()
{
    var builder = new ContainerBuilder();

    builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());

    var container = builder.Build();

    var testClass = container.Resolve<TestClass>();

    var obj1 = testClass.Get();
    var obj2 = testClass.Get();

    Assert.AreNotEqual(obj1, obj2);
}
Tags:  , ,

Answer

  1. Avatar for davy.ai

    El problema con la prueba que utiliza AutoMock falla porque AutoMock devuelve el mismo objeto cuando se llama factory(). Esto es porque AutoMock está diseñado para ser utilizado en pruebas unitarias y cachea instancias de dependencias para mejorar la velocidad de la prueba y reducir el uso de memoria. Sin embargo, esto puede crear problemas al probar clases que tienen dependencias en Func<t>, ya que la función necesita generar un nuevo objeto del tipo T cada vez que se llama.

    Para solucionar este problema, se puede crear un Func<t> personalizado que devuelva una nueva instancia de T cada vez que se llame. Aquí hay un ejemplo:

    public class TestClass
    {
        private readonly Func<testdep> factory;
    
        public TestClass(Func<testdep> factory)
        {
            this.factory = factory;
        }
    
        public TestDep Get()
        {
            return factory();
        }
    }
    
    public class TestDep
    {}
    
    [TestMethod]
    public void TestIt()
    {
        using var autoMock = AutoMock.GetStrict();
    
        // Cree una fábrica personalizada que devuelva una nueva instancia de TestDep cada vez que se llame
        var customFactory = new Func<testdep>(() => new TestDep());
    
        // Reemplace la instancia de la fábrica en el contenedor AutoMock con la fábrica personalizada
        autoMock.Provide(customFactory);
    
        var testClass = autoMock.Create<testclass>();
    
        var obj1 = testClass.Get();
        var obj2 = testClass.Get();
    
        Assert.AreNotEqual(obj1, obj2);
    }
    
    [TestMethod]
    public void TestIt2()
    {
        var builder = new ContainerBuilder();
    
        builder.RegisterType<testdep>();
    
        builder.RegisterType<testclass>()
            .WithParameter(
                (pi, ctx) => pi.ParameterType == typeof(Func<testdep>),
                (pi, ctx) => new Func<testdep>(() => ctx.Resolve<testdep>())
            );
    
        var container = builder.Build();
    
        var testClass = container.Resolve<testclass>();
    
        var obj1 = testClass.Get();
        var obj2 = testClass.Get();
    
        Assert.AreNotEqual(obj1, obj2);
    }
    

    En la primera prueba, creamos una fábrica personalizada que devuelve una nueva instancia de TestDep cada vez que se llama. Luego, reemplazamos la instancia de Func<testdep> en el contenedor de AutoMock con la fábrica personalizada antes de crear la instancia de TestClass. Esto asegura que Get() genere una nueva instancia de TestDep cada vez que se llama.

    En la segunda prueba, registramos TestDep y TestClass con el contenedor AutoFac. Usamos el método WithParameter para inyectar un Func<testdep> personalizado que resuelve TestDep del contenedor cada vez que se llama. Nuevamente, esto asegura que Get() genere una nueva instancia de TestDep cada vez que se llama.

Comments are closed.