Iva*_*ono 5 c# moq xunit.net autofixture asp.net-core
我有一个具有以下签名的控制器:
public CustomerTypeController(
IHttpContextAccessor accessor,
IPrincipalProvider provider,
IMapper mapper,
ILogger<CustomerTypeController> logger,
ICustomerTypeService customerTypeService)
{ }
Run Code Online (Sandbox Code Playgroud)
现在我的Theory样子是这样的:
[Theory, AutoMoqData]
public void GetWhenHasCustomerTypesShouldReturnOneCustomerType(
IFixture fixture,
[Frozen] Mock<ICustomerTypeService> service,
CustomerTypeController sut)
{
//Arrange
var items = fixture.CreateMany<Model.CustomerType>(3).ToList();
//Act
var result = sut.Get(1);
//Assert
Assert.IsType<OkResult>(result);
}
Run Code Online (Sandbox Code Playgroud)
当我按原样运行此测试时,出现以下异常:
AutoFixture.ObjectCreationExceptionWithPath : AutoFixture 无法从 Microsoft.AspNetCore.Mvc.ModelBinding.BindingInfo 创建实例,因为创建意外失败并出现异常。请参考内部异常来排查失败的根本原因。
内部异常消息:System.Reflection.TargetInitationException:调用目标已引发异常。System.ArgumentException:类型“System.Object”必须实现“Microsoft.AspNetCore.Mvc.ModelBinding.IModelBinder”才能用作模型绑定器。(参数“值”)
我做错了什么,我该如何解决这个问题?
您应该使用属性来装饰测试方法中的控制器参数[NoAutoProperties]。
[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);
}
Run Code Online (Sandbox Code Playgroud)
现在我对 AutoFixture 代码库有了更好的了解,我想了解为什么这实际上可以解决问题。
该Greedy属性通常指示 AutoFixture 使用参数最多的构造函数,这应该与修复无关。
正如错误消息所述,当设置属性并且该属性期望实现IModelBinder. 错误的根源是BinderType该类的属性BindingInfo,该属性的类型为System.Type。默认情况下,AutoFixture 将解析Type为System.Object,这解释了错误消息。
应用该Greedy属性时,会使用自定义工厂自定义 AutoFixture 以创建属性类型的实例。生成的构建器图节点(可能是意外)会跳过在创建的实例上设置任何属性。
考虑到这一点,更合适的解决方案应该是使用该NoAutoProperties属性。这将显式指示 AutoFixture 忽略修饰类型中的所有自动属性,但会将构造函数查询保留为“适度”。
由于在任何地方添加属性可能会变得烦人和乏味,因此我建议自定义 AutoFixture 以忽略ControllerBase域自定义中的所有属性。另外,如果您使用属性注入,这将允许 AutoFixture 实例化控制器属性。
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));
}
}
Run Code Online (Sandbox Code Playgroud)
如果您出于某种原因需要这些属性,ControllerBase那么只需指示 AutoFixture 如何正确创建BindingInfo实例即可。
您应该使用属性来装饰测试方法中的控制器参数[Greedy]。
[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);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2635 次 |
| 最近记录: |