简体   繁体   English

Autofac 容器更新和 Mock 依赖项

[英]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.作为集成测试的一部分,我想用 Autofac 包装一个已注册的类,以便我可以跟踪该类上发生的情况并将操作重定向到原始实现。

In the following example, I create a first container which the real app container and then create a spyContainer.在下面的示例中,我创建了第一个容器,即真正的应用程序容器,然后创建了一个 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 .该spyContainer应该重用的registeredInstance NameRetriever还有WorldLoggerWorldLogger应注射一HelloLoggerSpy本身应该被实例化与原来的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?任何人都知道如何在这里实现这一目标以及未来如何实现?

It looks like HelloLoggerSpy acts like the decorator pattern and Autofac has native support for such a pattern.看起来HelloLoggerSpy行为类似于装饰器模式,而Autofac对这种模式有本机支持。

Instead of your custom registration for HelloLoggerSpy you can use :您可以使用以下HelloLoggerSpy代替HelloLoggerSpy的自定义注册:

builder.RegisterDecorator<HelloLoggerSpy, IHelloLogger>();` 

See Adapter and Decorators from the Autofac documentation for more information有关更多信息,请参阅 Autofac 文档中的适配器和装饰器

You can't build a container multiple time but you can create a childlifetime scope and register stuff on this new stuff.你不能多次构建一个容器,但你可以创建一个 childlifetime 范围并在这个新东西上注册东西。

using(var scope = realContainer.BeginLifetimeScope(b => {
     b.RegisterDecorator<HelloLoggerSpy, IHelloLogger>(); 
}))
{
    scope.Resolve<IHelloLogger>(); // => HelloLoggerSpy
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM