Question

In an attempt to DRY up my unit tests, I'm trying to use AutoFixture as an IoC container to instantiate my system under test (SUT), which in this particular case are ASP.NET MVC Controllers. Therefore, I want to customize AutoFixture to create controllers without auto-properties.

I tried adding a customization for ControllerBase, but it doesn't seem to work for subclasses of ControllerBase.

fixture.Customize<ControllerBase>(c => c.OmitAutoProperties());

Here's an example of the test I want to be able to write:

    [Theory, AutoFixtureData]
    public void ControllerTest(AccountController controller) {
        Assert.Equal(default(UrlHelper), controller.Url);
    }

Naturally, it works if I manually add one customization for each specific controller in my project, but who wants to do that? Is there a better way?

Was it helpful?

Solution

The following Customization passes the above test, and does what you seem to ask

public class MvcCostumization : ICustomization
{
    public void Customize(IFixture fixture)
    {
        fixture.Customizations.Add(
            new FilteringSpecimenBuilder(
                new MethodInvoker(new ModestConstructorQuery()),
                new ControllerSpecification()));
    }

    private class ControllerSpecification : IRequestSpecification
    {
        public bool IsSatisfiedBy(object request)
        {
            var t = request as Type;
            if (t == null)
                return false;

            return typeof(ControllerBase).IsAssignableFrom(t);
        }
    }
}

However, that disables all properties of all MVC Controllers, including User, HttpContext, ModelState, Request, Response, etc. You might need those in unit tests, so are you sure you want to do that?

I'll be the first person to agree that the MVC Controller base class is one huge SRP violation, but it's a class which is given to us, so there's nothing we can do about except trying to make the best of it.

Usually, you only need to twist it a little to make AutoFixture fill most of the properties automatically.

In MVC 3 projects, this, combined with the AutoMoq extension, is sufficient to create Controller instances:

fixture.Customize<ModelBindingContext>(c => c
    .Without(x => x.Model)
    .Without(x => x.ModelType));
fixture.Inject(CultureInfo.CurrentCulture);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top