TL;DR
You should decorate the controller parameter in your test method with the [NoAutoProperties]
attribute.
[Theory, AutoMoqData]
public void GetWhenHasCustomerTypesShouldReturnOneCustomerType(
IFixture fixture,
[Frozen] Mock<ICustomerTypeService> service,
[NoAutoProperties] CustomerTypeController sut)
{
//Arrange
var items = fixture.CreateMany<Model.CustomerType>(3).ToList();
//Act
var result = sut.Get(1);
//Assert
Assert.IsType<OkResult>(result);
}
Update
Now that I know the AutoFixture code-base a little better, I wanted to understand why does this actually fix the issue.
The Greedy
attribute normally instructs AutoFixture to use the constructor with the largest number of parameters, which should have nothing to do with the fix.
As the error message states, the exception occurs when a property is being set and the property is expecting a value that implements IModelBinder
. The origin of the error is the BinderType
property of the BindingInfo
class, which is of type System.Type
. By default AutoFixture will resolve Type
as System.Object
, which explains the error message.
When the Greedy
attribute is applied, this customizes AutoFixture to create an instance of the property type, using a custom factory. The resulting builder graph node, (likely by accident) skips setting any properties, on the created instance.
Taking this into consideration, a more fitting resolution should be a using the NoAutoProperties
attribute. This will explicitly instruct AutoFixture to ignore all auto-properties in the decorated type, but will leave the constructor query as “modest”.
Since adding the attribute everywhere might get annoying and tedious, I suggest customizing AutoFixture to ignore all properties from ControllerBase
, in the domain customization. Also in case you’re using property injection, this will allow AutoFixture to instantiate the controller properties.
public class AutoMoqDataAttribute : AutoDataAttribute
{
public AutoMoqDataAttribute()
: base(() => new Fixture().Customize(
new CompositeCustomization(
new AutoMoqCustomization(),
new AspNetCustomization())))
{
}
}
public class AspNetCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Customizations.Add(new ControllerBasePropertyOmitter());
}
}
public class ControllerBasePropertyOmitter : Omitter
{
public ControllerBasePropertyOmitter()
: base(new OrRequestSpecification(GetPropertySpecifications()))
{
}
private static IEnumerable<IRequestSpecification> GetPropertySpecifications()
{
return typeof(ControllerBase).GetProperties().Where(x => x.CanWrite)
.Select(x => new PropertySpecification(x.PropertyType, x.Name));
}
}
If you need the properties in ControllerBase
for some reason then just instruct AutoFixture how to properly create BindingInfo
instances.
Original answer
You should decorate the controller parameter in your test method with the [Greedy]
attribute.
[Theory, AutoMoqData]
public void GetWhenHasCustomerTypesShouldReturnOneCustomerType(
IFixture fixture,
[Frozen] Mock<ICustomerTypeService> service,
[Greedy] CustomerTypeController sut)
{
//Arrange
var items = fixture.CreateMany<Model.CustomerType>(3).ToList();
//Act
var result = sut.Get(1);
//Assert
Assert.IsType<OkResult>(result);
}
CLICK HERE to find out more related problems solutions.