如何让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()));