1

My case is quite common but i cannot find an answer. I have integration tests where on each setup some services are mocked. I have to update Autuofac container to get constructor injection of those mocks. So basically I have main container with all application registration and need to create some child container/lifetime scope for those overridden services for each test scenario. I have registered custom 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;
        }
    }
}

which is invoked from static constructor

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); holds all initial registrations

and have some mock creation logic which registers new mock on each test setup

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

also i have disposing logic on TearDown

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

but thing is even if child scope gets disposed after each test all registrations stays in main container. So when i run tests where service implementation should not be mocked and there is some mock registered from previous tests on this interface it gets used.

I cannot build container on each test setup because my parent class creates transaction for test reverting so i need to build container in static constructor which runs first to solve all IRepository interfaces and etc.

I have also tried BeginLifetimeScope(c => ...) technique but also without success

Any thoughts someone? Thanks

p.s. i use Autofac 3.0.1 version and MVC 4

1 Answers1

0

I have actually come to the way to do this (not sure if this right way but it works)

To the TestLifeScopeProvider add these methods:

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

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

        return testlifeScope ?? lifetimeScope;
    }

To the TestBase setup add this code:

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

Hope this helps fore someone to save some time and headache :)

  • I was having the same issue, but this explanation is incomplete. Can you edit this and post all your code please? – r3plica Feb 12 '18 at 10:25