mercredi 25 décembre 2019

Autofac Container Update and Mock dependencies

As part of integration testing I would like to wrap a registered class with Autofac so that I can track what happens on that class and redirect the operations to the original implementation.

In the following example, I create a first container which the real app container and then create a spyContainer.

The spyContainer should reuse the registeredInstance of NameRetriever as well as the WorldLogger but the WorldLogger should be injected a HelloLoggerSpy which itself should have been instanciated with the original IHelloLogger.

public class NameRetriever
{
    public string GetName()
    {
        return "linvi";
    }
}

public interface IHelloLogger
{
    void Hello();
}

public class HelloLogger : IHelloLogger
{
    private readonly NameRetriever _nameRetriever;

    public HelloLogger(NameRetriever nameRetriever)
    {
        _nameRetriever = nameRetriever;
    }

    public void Hello()
    {
        Console.WriteLine("Hello " + _nameRetriever.GetName());
    }
}

public class WorldLogger
{
    private readonly IHelloLogger _helloLogger;

    public WorldLogger(IHelloLogger helloLogger)
    {
        _helloLogger = helloLogger;
    }

    public void World()
    {
        _helloLogger.Hello();
        Console.WriteLine("Welcome in this world");
    }
}

public class HelloLoggerSpy : IHelloLogger
{
    private readonly IHelloLogger _sourceHelloLogger;
    public bool Called { get; private set; }

    public HelloLoggerSpy(IHelloLogger sourceHelloLogger)
    {
        _sourceHelloLogger = sourceHelloLogger;
    }

    public void Hello()
    {
        _sourceHelloLogger.Hello();
        Called = true;
    }
}

static void Main()
{
    var containerBuilder = new ContainerBuilder();
    // This is normal container creation
    containerBuilder.RegisterInstance(new NameRetriever());
    containerBuilder.RegisterType<HelloLogger>().As<IHelloLogger>();
    containerBuilder.RegisterType<WorldLogger>();

    var realContainer = containerBuilder.Build();

    // This is something that would be invoked during tests
    // to override the A behaviour
    containerBuilder.Register<IHelloLogger>(context =>
    {
        var realA = context.Resolve<IHelloLogger>(); // recursive as IA is not yet reusing the previous one
        var aSpy = new HelloLoggerSpy(realA);
        return aSpy;
    });

    var spyContainer = containerBuilder.Build(); // cannot build twice

    var b = spyContainer.Resolve<WorldLogger>();
    b.World(); // should have called  HelloLoggerSpy.Hello()
}

Anyone knows how to achieve this here and how will this be possible in the future?

Aucun commentaire:

Enregistrer un commentaire