Override Autofac registration - Integration tests

2020-03-21 01:55发布

问题:

I write integration tests for my application, and use my container for this. I want to be able to register all the components as I do in real running, and then override some of the components and switch them to use stubs implementations.

I wouldn't want to seperate the DI and have a container for tests only because I want to test the real thing.

Doing this also seems ugly:

public class MyRegistrations
{
     public static RegisterAll(bool isInTest= false)
     {
           if (isTest) 
           {
             // Register test fakes
            }
            else
                  // Register real components
      }
}

So I thought of overriding registrations in my test enviorment. How should it be done?

Any other better ways for achieving my goal?

Thanks

回答1:

Autofac will use the last registered component as the default provider of that service

From the AutoFac documation.

In your arrange/setup/testInit phase register the mocks, then resolve the SUT:

[SetUp]
public void TestInit()
{
    Mock<IFoo> mock = new Mock<IFoo>();
    builder.RegisterInstance(mock.object).As<IFoo>();
    ...
    ...
    _target = builder.Resolve<The component>();
}

Note:

Singletons, static members and SingletonLifestyle(registration) may cause some troubles....



回答2:

Well, for example you can create a static action method inside your composition root to alter the current configuration and call it during testing. For example:

public class CompositionRoot
{
    public static Action<IContainer> OverrideContainer = c => { };

    internal static IContainer CreateContainer()
    {
        ContainerBuilder builder = new ContainerBuilder();

        /// etc. etc.

        var container = builder.Build();

        OverrideContainer(container);

        return container;
    }
}

After that you can create a mock of you server, for example, like this:

[TestFixture]
public class ConfigurationControllerFixture : BaseServer
{
    [Test]
    public async Task verify_should_get_data()
    {
        var response = await GetAsync(Uri);
        Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
    }

    protected override string Uri
    {
        get { return "api/configuration"; }
    }
}

public abstract class BaseServer
{
    protected TestServer Server;
    protected abstract string Uri { get; }

    protected virtual void OverrideConfiguration()
    {
        CompositionRoot.OverrideContainer = c =>
        {
            // new autofac configuration
            cb.Update(c);
        };

        AppStartup.OverrideConfiguration = c =>
        {
            // same as explained, but for HttpConfiguration
        };
    }
}

[SetUp]
public void Setup()
{
    OverrideConfiguration();

    Server = Microsoft.Owin.Testing.TestServer.Create(app =>
    {
       var startup = new AppStartup();
            startup.Configuration(app);
    });

    PostSetup(Server);
}

Hope it helps :)