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

Roo*_*ian 9 c# test-data autofixture

我有这样一堂课:

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

public class SearchFilter
{
    public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

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

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

var context = new SpecimenContext(fixture.Compose());
var value = context.Resolve(new SeededRequest(typeof(ViewModel), null))
Run Code Online (Sandbox Code Playgroud)

Dan*_*rth 5

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

fixture.Register<YourInterface>(() =>  new InterfaceImpl());
Run Code Online (Sandbox Code Playgroud)

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

  • AutoMoq定制
  • AutoRhinoMock定制
  • AutoFakeItEasy定制

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

fixture.Register(() => (IPagination<Data>)new Pagination(
                                            fixture.CreateMany<Data>()));
Run Code Online (Sandbox Code Playgroud)


Nik*_*nis 4

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

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

public interface IPagination<T>
{
    SearchFilter Property1 { get; set; }
    string Property2 { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我们可以创建一个临时的自动模拟定制,例如MyCustomization

var fixture = new Fixture()
    .Customize(new MyCustomization());
var context = new SpecimenContext(fixture.Compose());
Run Code Online (Sandbox Code Playgroud)

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

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

我的定制

在应用此自定义之前,请记住,这应该仅适用于此特定场景(因此是描述中的临时场景)。我强烈建议在其他地方使用 Auto Mocking、 AutoMoqAutoRhinoMocksAutoFakeItEasyAutoNSubstitute的扩展之一。

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<TRequest>(ISpecimenContext context)
            where TRequest : class
        {
            var mock = new Mock<TRequest>();
            mock.SetupAllProperties();

            foreach (PropertyInfo propInfo in typeof(TRequest).GetProperties())
            {
                object value = context.Resolve(propInfo.PropertyType);
                propInfo.SetValue(mock.Object, value);
            }
            return mock.Object;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 调用 `mock.SetupAllProperties()` 不是更容易一点吗? (2认同)