【问题标题】:How to let Autofixture create an instance of a type that contains properties with an interface type?如何让 Autofixture 创建包含具有接口类型的属性的类型的实例?
【发布时间】:2012-10-08 14:27:15
【问题描述】:

我有这样的课:

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; }
}

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

现在我知道我可以做到这一点:

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

【问题讨论】:

  • 你最后一个问题的视图模型和答案与最后一句实际上是问题有什么关系?请重点关注您的问题。
  • 你说得对,我脑子里有很多问题:)

标签: c# autofixture test-data


【解决方案1】:

简单的可能性是注册出厂方法:

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

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

  • AutomoqCustomization Li>
  • autorhinocockcustomization Li>
  • AutofakeIteasyCustomization Li>

在具体情况下,这将创建表示空列表的接口的实例。
当您希望在该列表中具有测试数据时,您不希望使用自动模拟自定义,但是根据第987654321 @ IPagination的语义来使用自动定制。 如果这太复杂,您仍然可以使用Register方法:

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

【讨论】:

  • 也可以让AutoFixture在接口周围创建动态代理并用测试数据填充它? span>
  • 是否可以使用数据填充创建的代理列表? span>
【解决方案2】:

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

假设ViewModel类型的IPagination&lt;T&gt;属性定义为:

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

我们可以创建一个 ad-hoc 自动模拟自定义,例如MyCustomization.

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

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

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

我的自定义

在应用此自定义之前,请记住这仅适用于此特定场景(因此描述中的 ad-hoc)。我强烈建议使用 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;
        }
    }
}

【讨论】:

  • 调用mock.SetupAllProperties()会不会容易一点?
  • 只是让实现更加简单。
  • 这里是another approach,描述了如何配置AutoFixture.AutoMoq 来设置所有模拟实例以及自动填充它们的属性。
猜你喜欢
  • 1970-01-01
  • 2015-08-25
  • 1970-01-01
  • 2013-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多