问题
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.
回答1:
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.
来源:https://stackoverflow.com/questions/12605977/autofixture-and-webapi-controller