Pregunta

I am using AutoFixture to try to test my controllers for a WebApi site. I am using the AutoData feature with Moq as noted on Ploeh's blog.

My controller takes an IDepartmentManager in the constructor. Here is my test:

[Theory, AutoMoqData]
public void GetCallsManagerCorrectly(
    [Frozen]Mock<IDepartmentManager> departmentManagerMock,
    DepartmentsController sut)
{
    // Fixture setup
    // Exercise system
    sut.Get();
    // Verify outcome
    departmentManagerMock.Verify(d => d.GetAllDepartments(), Times.Exactly(1));
    // Teardown
}

When I run this test it fails with the following:

GetCallsManagerCorrectly has failed:
System.InvalidOperationException : An exception was thrown while getting data for theory Provision.Tests.WebApiControllerTests.DepartmentControllerTests.GetCallsManagerCorrectly: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ArgumentException: Only 'http' and 'https' schemes are allowed. Parameter name: value at System.Net.Http.HttpRequestMessage.set_RequestUri(Uri value)

First of all, is this still a valid and recommended way to write these tests? I love how small it makes everything.

Secondly, what should I do to fix this? If I change my test to this:

[Theory, AutoMoqData]
public void GetCallsManagerCorrectly(
    [Frozen]Mock<IDepartmentManager> departmentManagerMock)
{
    // Fixture setup
    DepartmentsController sut =
        new DepartmentsController(departmentManagerMock.Object);
    // Exercise system
    sut.Get();
    // Verify outcome
    departmentManagerMock.Verify(d => d.GetAllDepartments(), Times.Exactly(1));
    // Teardown
}

it passes, but then I lose the ability to have the controller built up automatically and still be ok if I add parameters to the constructor.

¿Fue útil?

Solución

This is definitely the recommended way to write tests with AutoFixture. The issue is pretty easy to fix.

Instead of implementing the [AutoMoqData] attribute as described in the blog post, I'd recommend creating a slightly different attribute and Customization - a set that basically will act as a set of conventions for an entire unit test project. I always do this, and I always go to great lengths to have only a single set of conventions for a single unit test project. A single set of conventions help me keep my tests (and the SUTs) consistent.

public class AutoMyWebApiDataAttribute : AutoDataAttribute
{
    public AutoMyWebApiDataAttribute()
        : base(new Fixture().Customize(new MyWebApiCustomization()))
    {
    }
}

The MyWebApiCustomization could be defined like this:

public class MyWebApiCustomization : CompositeCustomization
{
    public MyWebApiCustomization()
        : base(
            new HttpSchemeCustomization(),
            new AutoMoqCustomization(),
        )
    {
    }

    private class HttpSchemeCustomization : ICustomization
    {
        public void Customize(IFixture fixture)
        {
            fixture.Inject(new UriScheme("http"));
        }
    }
}

Note the additional HttpSchemeCustomization class - that should do the trick.

Please note that the order of Customizations matters.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top