1

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

有人有什么想法吗?谢谢

ps 我使用 Autofac 3.0.1 版本和 MVC 4

4

1 回答 1

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();
    }

希望这可以帮助某人节省一些时间和头痛:)

于 2013-07-10T11:44:04.973 回答