3

我有一个 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 ...
        }    
    }
}

我的问题是:如何通过模拟(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.ILifetimeScope 的“ On Fly ”构建功能并使用 LifeTime 范围参数设计 ServiceClass 构造函数。通过这种设计,我可以在单元测试中即时注册任何服务,如下例所示:

using(var scope = Ioc.BeginLifetimeScope(
    builder =>  builder.RegisterInstance(mockObject).As<ITimeConsume>())
4

2 回答 2

4

在当前设计中,您无法注入模拟对象。更改最少的最简单解决方案是将InternalCto'r 添加到ServiceClass

internal ServiceClass(IContainer ioc)
{
    _ioc = ioc;     
}

然后使用该属性InternalsVisibleTo在您的测试类中启用 C`tor 的使用。

在安排/设置/测试初始化​​阶段,使用包含模拟对象的容器初始化您的测试类:

    [SetUp]
    public void TestInit()
    {
        Mock<ITimeConsume> moc = GetMockObj(...);
        builder.RegisterInstance(moc).As<ITimeConsume>();
        ...
        ...
        _target = new ServiceClass(builder.Build());
    }
于 2015-07-14T10:00:41.270 回答
1

我个人有多个容器实例。每个端点一个。

测试项目

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>();
}
于 2015-07-14T10:02:29.593 回答