如何让Autofixture创建一个包含接口类型属性的类型的实例?

我有这样一堂课:

public class ViewModel { public IPagination List { get; set; } // interface! public SearchFilter SearchFilter { get; set; } public string Test { get; set; } } public class SearchFilter { public string Name { get; set; } } 

应在IPagination接口周围创建动态代理,代理应填充测试数据。 现在可以让AutoFixture创建一个ViewModel类型的实例吗? 请注意,我只知道运行时的类型( typeof(ViewModel) )。

到现在为止我知道我可以这样做:

 var context = new SpecimenContext(fixture.Compose()); var value = context.Resolve(new SeededRequest(typeof(ViewModel), null)) 

从理论上讲,应该可以填充自动模拟实例的属性。

假设ViewModel类型的IPagination属性定义为:

 public interface IPagination { SearchFilter Property1 { get; set; } string Property2 { get; set; } } 

我们可以创建一个特殊的自动模拟自定义,例如MyCustomization

 var fixture = new Fixture() .Customize(new MyCustomization()); var context = new SpecimenContext(fixture.Compose()); 

然后,以下调用将创建ViewModel的实例(仅在运行时知道) ,提供IPagination的自动模拟实例并为属性赋值。

 var value = context.Resolve(typeof(ViewModel)); // List -> {IPagination`1Proxy593314cf4c134c5193c0019045c05a80} // List.Property1.Name -> "Namef71b8571-a1a0-421d-9211-5048c96d891b" // List.Property2 -> "f58cae65-b704-43ec-b2ce-582a5e6177e6" 

MyCustomization

在应用此自定义之前,请记住,这应仅适用于此特定方案(因此说明中的ad-hoc )。 我强烈建议在其他地方使用Auto Mocking, AutoMoq , AutoRhinoMocks , AutoFakeItEasy或AutoNSubstitute的扩展名之一

 internal class MyCustomization : ICustomization { public void Customize(IFixture fixture) { fixture.Customizations.Add(new MySpecimenBuilder()); } private class MySpecimenBuilder : ISpecimenBuilder { public object Create(object request, ISpecimenContext context) { var type = request as Type; if (type == null || !type.IsInterface) { return new NoSpecimen(request); } object specimen = this .GetType() .GetMethod( "Create", BindingFlags.NonPublic | BindingFlags.Static) .MakeGenericMethod(new[] { type }) .Invoke(this, new object[] { context }); return specimen; } private static object Create(ISpecimenContext context) where TRequest : class { var mock = new Mock(); mock.SetupAllProperties(); foreach (PropertyInfo propInfo in typeof(TRequest).GetProperties()) { object value = context.Resolve(propInfo.PropertyType); propInfo.SetValue(mock.Object, value); } return mock.Object; } } } 

一种简单的可能性是注册工厂方法:

 fixture.Register(() => new InterfaceImpl()); 

要让AutoFixture自动为您想要使用其中一个自动模拟自定义的接口创建代理:

  • AutoMoqCustomization
  • AutoRhinoMockCustomization
  • AutoFakeItEasyCustomization

在具体情况下,这将创建一个表示空列表的接口实例。
当您希望在该列表中包含测试数据时,您不希望使用自动模拟自定义,而是使用了解本文中所述的IPagination语义的自定义。
如果这太复杂,您仍然可以使用Register方法:

 fixture.Register(() => (IPagination)new Pagination( fixture.CreateMany()));