I am trying to auto mock ApiController class in my test cases. It worked perfectly when I was using WebApi1. I started to use WebApi2 on the new project and I am getting thi
Note: The original answer requires the same customization to be copied for each new ApiController.
Generalized approach
An alternative way is to automatically fill the Request
property on all ApiControllers (thus saving you from cut, copy, and paste):
internal class ApiControllerCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customizations.Add(
new FilteringSpecimenBuilder(
new Postprocessor(
new MethodInvoker(
new ModestConstructorQuery()),
new ApiControllerFiller()),
new ApiControllerSpecification()));
}
private class ApiControllerFiller : ISpecimenCommand
{
public void Execute(object specimen, ISpecimenContext context)
{
if (specimen == null)
throw new ArgumentNullException("specimen");
if (context == null)
throw new ArgumentNullException("context");
var target = specimen as ApiController;
if (target == null)
throw new ArgumentException(
"The specimen must be an instance of ApiController.",
"specimen");
target.Request =
(HttpRequestMessage)context.Resolve(
typeof(HttpRequestMessage));
}
}
private class ApiControllerSpecification : IRequestSpecification
{
public bool IsSatisfiedBy(object request)
{
var requestType = request as Type;
if (requestType == null)
return false;
return typeof(ApiController).IsAssignableFrom(requestType);
}
}
}
The value of type HttpRequestMessage
, for the Request
property, is built using the following customization:
internal class HttpRequestMessageCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customize<HttpRequestMessage>(c => c
.Without(x => x.Content)
.Do(x => x.Properties[HttpPropertyKeys.HttpConfigurationKey] =
new HttpConfiguration()));
}
}
Packing everything into a composite Customization
Create a Customization composite as below - note that the order of AutoFixture Customizations matter:
internal class ApiControllerConventions : CompositeCustomization
{
internal ApiControllerConventions()
: base(
new HttpRequestMessageCustomization(),
new ApiControllerCustomization(),
new AutoMoqCustomization())
{
}
}
Hope that helps.
Note:
Assuming that the UserController
class takes an IUserModel
through its constructor.
As it looks like, the default constructor of ApiController
performs some work (probably more than simple assignments).
If the UserController
class takes an IUserModel
through its constructor, you can pick that constructor (the greediest) instead.
Update:
Replace the HttpRequestMessageCustomization
customization with:
internal class ApiControllerCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customize<HttpRequestMessage>(c => c
.Without(x => x.Content)
.Do(x => x.Properties[HttpPropertyKeys.HttpConfigurationKey] =
new HttpConfiguration()));
fixture.Customize<UsersController>(c => c
.OmitAutoProperties()
.With(x => x.Request, fixture.Create<HttpRequestMessage>()));
}
}
And the original test will execute fine.
Based on Nikos' answer:
This is a more generic way of using this customization where the controller type can be supplied and the Customization
can be used for any controller
internal class WebApiCustomization<TControllerType> : ICustomization
where TControllerType : ApiController
{
public void Customize(IFixture fixture)
{
fixture.Customize<HttpRequestMessage>(c => c
.Without(x => x.Content)
.Do(x => x.Properties[HttpPropertyKeys.HttpConfigurationKey] =
new HttpConfiguration()));
fixture.Customize<TControllerType>(c => c
.OmitAutoProperties()
.With(x => x.Request, fixture.Create<HttpRequestMessage>()));
}
}
Then use as follows:
var fixture = new Fixture().Customize(
new WebApiCustomization<UsersController>());
var sut = fixture.Create<UsersController>();