Lets start with simple controller:
[Route("api/[controller]") public class TestController : Controller { [HttpGet("")] public IActionResult Get() { return Ok(); } }
Now we want to create unit test for this method using AutoFixture/Moq/Shouldly/XUnit stack:
public class TestControllerTests { [Theory, AutoMoqData] public void Get_ShouldReturn_HttpStatusOk(TestController sut) { // act.. var actual = sut.Get(); // assert.. actual.ShouldNotBeNull(); actual.ShouldBeOfType() } }
Test runner will crash saying:
AutoFixture.ObjectCreationException : AutoFixture was unable to create an instance from Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary because creation unexpectedly failed with exception. Please refer to the inner exception to investigate the root cause of the failure. Request path: J2BI.Holidays.TravelDocs.Api.Controllers.AccommodationController sut --> J2BI.Holidays.TravelDocs.Api.Controllers.AccommodationController --> Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary ViewData --> Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary ---- System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation. -------- Castle.DynamicProxy.InvalidProxyConstructorArgumentsException : Can not instantiate proxy of class: Microsoft.AspNetCore.Mvc.ModelBinding.ModelMetadata. Could not find a parameterless constructor.
The problem lies in lack of parameterless constructor for ModelMetadata class.
This can easily be fixed with AutoFixture customization:
public class ApiControllerCustomization : ICustomization { public void Customize(IFixture fixture) { fixture.Register(() => new CustomCompositeMetadataDetailsProvider()); fixture.Inject(new ViewDataDictionary(fixture.Create(), fixture.Create())); } private class CustomCompositeMetadataDetailsProvider : ICompositeMetadataDetailsProvider { public void CreateBindingMetadata(BindingMetadataProviderContext context) { throw new System.NotImplementedException(); } public void CreateDisplayMetadata(DisplayMetadataProviderContext context) { throw new System.NotImplementedException(); } public void CreateValidationMetadata(ValidationMetadataProviderContext context) { throw new System.NotImplementedException(); } } }
This now has to be wrapped in data attribute:
public class AutoApiMoqDataAttribute : AutoDataAttribute { public AutoApiMoqDataAttribute() : base(() => { var fixture = new Fixture(); fixture.Customize(new ApiControllerCustomization()) .Customize(new AutoMoqCustomization()) .Behaviors.Add(new OmitOnRecursionBehavior()); return fixture; }) { } }
Voila! Now the test will pass.
Check out this gist