Autofac生命周期范围注册共享,集成测试设置

时间:2013-07-09 14:35:49

标签: unit-testing mocking integration-testing ioc-container autofac

我的情况很常见,但我找不到答案。 我有集成测试,在每个设置上都会模拟一些服务。我必须更新Autuofac容器以获取构造函数注入那些模拟。所以基本上我有所有应用程序注册的主容器,并且需要为每个测试场景为那些被覆盖的服务创建一些子容器/生命周期范围。我已经注册了自定义ILifetimeScopeProvider

public class TestLifetimeScopeProvider : ILifetimeScopeProvider
{
    readonly ILifetimeScope container;
    private ILifetimeScope lifetimeScope = null;
    private ILifetimeScope testlifeScope = null;

    public TestLifetimeScopeProvider(ILifetimeScope container)
    {
        if (container == null) throw new ArgumentNullException("container");
        this.container = container;
    }

    public ILifetimeScope ApplicationContainer
    {
        get { return container; }
    }

    public ILifetimeScope GetLifetimeScope()
    {
        if (lifetimeScope == null)
        {
            lifetimeScope = ApplicationContainer.BeginLifetimeScope("AutofacWebRequest");
        }

        if (testlifeScope == null)
        {
            testlifeScope = lifetimeScope.BeginLifetimeScope("TestLifeScope");
        }

        return testlifeScope;
    }

    public ILifetimeScope GetLifetimeScope(Action<ContainerBuilder> configurationAction)
    {
        return GetLifetimeScope();
    }

    public void EndLifetimeScope()
    {
        if (lifetimeScope != null)
            lifetimeScope.Dispose();
    }

    public void EndTestLifetimeScope()
    {
        if (lifetimeScope != null)
        {
            testlifeScope.Disposer.Dispose();
            lifetimeScope = null;
        }
    }
}

从静态构造函数

调用
static TestBase()
    {
        var builder = new ContainerBuilder();
        DependencyRegistrar.Register(builder);

        Container = builder.Build();

        LsProvider = new TestLifetimeScopeProvider(Container);
        DependencyResolver.SetResolver(new AutofacDependencyResolver(Container, LsProvider));


    }

DependencyRegistrar.Register(builder); 包含所有初始注册

并有一些模拟创建逻辑,在每个测试设置上注册新模拟

 builder.Register(c => mockInitializer.ServiceMock)
                            .As(mockInitializer.ServiceType)
                            .InstancePerMatchingLifetimeScope("TestLifeScope");
builder.Update(Container);

我也在TearDown处理逻辑

    [TearDown]
    public virtual void TearDown()
    {
        LsProvider.EndTestLifetimeScope();
    }

但是即使儿童范围在每次测试之后被处理所有的登记在主要的容器停留了的话也是这样。因此,当我运行测试时,不应该模拟服务实现,并且在此接口上有一些先前测试中注册的模拟,它会被使用。

我无法在每个测试设置上构建容器,因为我的父类为测试还原创建了事务,所以我需要在静态构造函数中构建容器,该构造函数首先运行以解决所有IRepository接口等。

我也尝试过BeginLifetimeScope(c =&gt; ...)技术,但也没有成功

有人想过吗? 感谢

P.S。我使用Autofac 3.0.1版本 和MVC 4

1 个答案:

答案 0 :(得分:0)

我实际上已经开始做到这一点(不确定这是否正确但是有效)

向TestLifeScopeProvider添加以下方法:

public void SetTestLifeTimeScope(ILifetimeScope lifeTimeScope)
    {
        testlifeScope = lifeTimeScope;
    }

    public ILifetimeScope GetLifetimeScope()
    {
        if (lifetimeScope == null)
        {
            lifetimeScope = ApplicationContainer.BeginLifetimeScope("AutofacWebRequest");
        }

        return testlifeScope ?? lifetimeScope;
    }

在TestBase设置中添加以下代码:

public void SetupServiceMocks()
    {
        if (ServiceMocks.Any())
        {
            var currentLifeScope = LsProvider.GetLifetimeScope();
            var newScope = currentLifeScope.BeginLifetimeScope(builder =>
                {
                    foreach (var mockInitializer in ServiceMocks)
                    {
                        if (mockInitializer.ServiceType != null)
                        {
                            builder.Register(c => mockInitializer.ServiceMock)
                                       .As(mockInitializer.ServiceType)
                                       .InstancePerLifetimeScope();
                        }
                    }
                });

            LsProvider.SetTestLifeTimeScope(newScope);
        }
    }

    [TearDown]
    public virtual void TearDown()
    {
        LsProvider.EndTestLifetimeScope();
    }

希望这能帮助有人节省时间和头痛:)