生成具有等效所有属性的复杂类型

时间:2017-11-07 18:27:49

标签: autofixture

AutoFixture 是否可以创建具有所有相同数据的给定类型的多个实例?我的类不可序列化,我需要两个不是引用等效的模型,而是具有匹配的属性。

public class Foo
{
    // Many more properties and similar models needing the same semantics.
    public string Name { get; set; }
}

var a = fixture.Create<Foo>();
var b = fixture.Create<Foo>();

Assert.False(ReferenceEquals(a, b));
Assert.Equal(a.Name, b.Name);

1 个答案:

答案 0 :(得分:0)

我不认为AutoFixture可以做到这一点,但Albedo可以。虽然这只是概念验证代码,但我希望它应该说明一般的想法。

创建一个新类,派生自public class PropertyCopyVisitor<T> : ReflectionVisitor<T> { private readonly T source; private readonly T destination; public PropertyCopyVisitor(T source, T destination) { this.source = source; this.destination = destination; } public override IReflectionVisitor<T> Visit( PropertyInfoElement propertyInfoElement) { var pi = propertyInfoElement.PropertyInfo; pi.SetValue(this.destination, pi.GetValue(this.source)); return this; } public override T Value { get { return this.destination; } } }

Visit

实施的关键部分是source重载,它使用Reflection将每个属性从destination复制到destination对象。

由于此实现会改变Value,因此永远不会使用abstract属性,但它必须存在,因为它ReflectionVisitor<T>中的var fixture = new Fixture(); var a = fixture.Create<Foo>(); var b = fixture.Create<Foo>(); // Or just create a new, empty Foo... // This copies all properties from a to b: new TypeElement(typeof(Foo)).Accept(new PropertyCopyVisitor<Foo>(a, b)); Assert.False(ReferenceEquals(a, b)); Assert.Equal(a.Name, b.Name); ...

您现在可以将测试编写为:

fixture

在这里,我仍然使用b来创建Foo,但您不必这样做,因为无论如何都会覆盖所有属性。如果new Foo()具有无参数构造函数,则可以简单地使用Visit;它没有任何区别。

此概念验证明确仅复制属性。如果您还需要复制字段,那么您也必须覆盖相应的new TypeElement(typeof(Foo)).Accept(new PropertyCopyVisitor<Foo>(a, b));方法。此外,如果有问题的对象采用构造函数参数,那么您也需要明确地处理这些对象。

如果你发现写PropertyCopyVisitor很乏味,我相信你可以找到一种方法来编写辅助方法。

作为补充说明,T 是通用的,因为它实际上并没有使用{{1}}类型参数。我只是喜欢它给构造函数的类型安全性......