使用mock (Moq)对象更改Autofac模块中的注入
本文关键字:模块 Autofac 注入 mock Moq 对象 使用 | 更新日期: 2023-09-27 18:02:46
我有一个Autofac模块,如下图
public class ServiceInjector:Module
{
protected override void Load(ContainerBuilder builder)
{
// many registrations and type looking up here
...
// One of the registration, say t which is found
// in above looking, is a resource consuming type
builder.RegisterType(t).As<ITimeConsume>();
// ...
}
}
这个模块在ServiceClass中使用:
public class ServiceClass
{
static IContainer _ioc;
public ServiceClass()
{
var builder = new ContainerBuilder();
builder.RegisterModule<ServiceInjector>();
_ioc = builder.Build();
}
public void InvokeService()
{
using(var scope = _ioc.BeginLifetimeScope())
{
ITimeConsume obj = scope.Resolve<ITimeConsume>(...);
var result = obj.DoTimeConsumingJob(...);
// do something about result here ...
}
}
}
我的问题是:我如何通过mock (Moq) ITimeConsume类测试ServiceClass ?这里我试着在下面写一个测试:
public void Test()
{
Mock<ITimeConsume> moc = GetMockObj(...);
// How can I inject moc.Object into ServiceInjector module,
// so that ServiceClass can use this mock object ?
}
如果这是不可能的方式,有什么更好的设计来模拟耗时的类,也可以注入?
* *更新:
* *谢谢@dubs和@OldFox提示。我认为关键是Autofac注入器应该在外部初始化,而不是内部控制。所以我利用了Autofac的"On Fly"构建能力。使用LifeTime作用域参数设计ServiceClass构造函数。通过这种设计,我可以在单元测试中注册任何服务,示例如下:
using(var scope = Ioc.BeginLifetimeScope(
builder => builder.RegisterInstance(mockObject).As<ITimeConsume>())
在当前的设计中,您不能注入模拟对象。最简单、变化最少的解决方案是在ServiceClass
中添加一个Internal
Cto'r:
internal ServiceClass(IContainer ioc)
{
_ioc = ioc;
}
然后使用属性InternalsVisibleTo
来启用在测试类中使用C 'tor。
在arrange/setup/testInit阶段,用包含模拟对象的容器初始化被测类:
[SetUp]
public void TestInit()
{
Mock<ITimeConsume> moc = GetMockObj(...);
builder.RegisterInstance(moc).As<ITimeConsume>();
...
...
_target = new ServiceClass(builder.Build());
}
我个人有多个容器实例。每个端点一个。
测试项目public class AutofacLoader
{
public static void Configure()
{
var builder = new ContainerBuilder();
builder.RegisterModule<ServiceProject.ServiceInjector>();
builder.RegisterModule<LocalTestProject.AutofacModule>();
Container = builder.Build();
}
public static IContainer Container { get; set; }
}
本地测试项目autofac模块可以自由地用特定的注册覆盖服务项目模块。
测试类如果多个组件公开相同的服务,Autofac将使用最后注册的组件作为该服务的默认提供者:http://autofac.readthedocs.org/en/latest/register/registration.html#default-registrations
public void Test()
{
AutofacLoader.Configure();
var x = AutofacLoader.Container.Resolve<ITimeConsume>();
}