Autofac 容器更新和 Mock 依赖项
Autofac Container Update and Mock dependencies
作为集成测试的一部分,我想用 Autofac 包装一个已注册的 class,这样我就可以跟踪 class 上发生的事情,并将操作重定向到原始实现。
在下面的示例中,我创建了第一个容器,它是真正的应用程序容器,然后创建了一个 spyContainer。
spyContainer 应该重用 NameRetriever
和 WorldLogger
的 registeredInstance,但是 WorldLogger
应该注入一个 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()
}
任何人都知道如何在这里实现这一点以及将来如何实现?
看起来 HelloLoggerSpy
就像装饰器模式一样,Autofac 对这种模式有原生支持。
您可以使用 :
而不是 HelloLoggerSpy
的自定义注册
builder.RegisterDecorator<HelloLoggerSpy, IHelloLogger>();`
有关详细信息,请参阅 Autofac 文档中的 Adapter and Decorators
您不能多次构建一个容器,但您可以创建一个 childlifetime 范围并在这个新内容上注册内容。
using(var scope = realContainer.BeginLifetimeScope(b => {
b.RegisterDecorator<HelloLoggerSpy, IHelloLogger>();
}))
{
scope.Resolve<IHelloLogger>(); // => HelloLoggerSpy
}
作为集成测试的一部分,我想用 Autofac 包装一个已注册的 class,这样我就可以跟踪 class 上发生的事情,并将操作重定向到原始实现。
在下面的示例中,我创建了第一个容器,它是真正的应用程序容器,然后创建了一个 spyContainer。
spyContainer 应该重用 NameRetriever
和 WorldLogger
的 registeredInstance,但是 WorldLogger
应该注入一个 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()
}
任何人都知道如何在这里实现这一点以及将来如何实现?
看起来 HelloLoggerSpy
就像装饰器模式一样,Autofac 对这种模式有原生支持。
您可以使用 :
而不是HelloLoggerSpy
的自定义注册
builder.RegisterDecorator<HelloLoggerSpy, IHelloLogger>();`
有关详细信息,请参阅 Autofac 文档中的 Adapter and Decorators
您不能多次构建一个容器,但您可以创建一个 childlifetime 范围并在这个新内容上注册内容。
using(var scope = realContainer.BeginLifetimeScope(b => {
b.RegisterDecorator<HelloLoggerSpy, IHelloLogger>();
}))
{
scope.Resolve<IHelloLogger>(); // => HelloLoggerSpy
}