如何为复杂对象的默认创建自定义 AutoFixture?

如何解决如何为复杂对象的默认创建自定义 AutoFixture?

我有一个相当大的类,使用实体框架和一些列表属性作为一对多关系。我使用 AutoFixture 创建测试数据并摆脱循环引用,我设置了很多“无”。但是要一遍又一遍地复制相同的代码。我不知道如何自定义初始创建。看起来像这样

作品:

  var entity = fixture.Build<MyObject>()
                .Without(c => c.Cars)
                .Without(c => c.Boats)
                .Without(c => c.Motorcycles)
                .Without(c => c.Skateboards)
                .Create();

我希望每次使用夹具创建 MyObject 时将这些设置为认值(然后在某些情况下可以覆盖它们)

我尝试创建一个这样的类

public class Conventions: ICustomization
{
    public void Customize(IFixture fixture)
    {

        fixture.Customize<MyObject>
        (c => c
                .Without(c => c.Cars)
                .Without(c => c.Boats)
                .Without(c => c.Motorcycles)
                .Without(c => c.Skateboards)
        );

然后使用它:

var fixture = new Fixture();

fixture.Customize(new Conventions());
var entity = fixture.Build<MyObjec>().Create();

但不,它在递归声明上失败

解决方法

您描述的行为是有意为之。 .Build<T>() 自定义会创建一次性使用的自定义,该自定义会忽略之前分配的所有自定义。

如果只是想使用以前应用的类型自定义来创建实例,那么您需要做的就是从测试中删除 .Build<T>() 语句并直接使用 .Create()。这将避免从头开始创建自定义。

var fixture = new Fixture();

fixture.Customize(new Conventions());
var entity = fixture.Create<MyObject>();

由于您使用的是 EntityFramework,因此您的导航属性很可能被标记为 virtual。您可以编写一个 IRequestSpecification 来标识虚拟成员并使用 Omitter 省略所有导航属性。

解决您的问题的另一种方法是考虑更改域模型的设计。例如,问问自己允许域模型的客户端“设置/替换”船的集合是否是有效的操作。如果答案为“否”,您可能想要更改模型,以便此规则反映在设计本身中,即将设置器设为私有并将集合更改为只读集合。如果您这样做,AutoFixture 将忽略导航属性,您将能够使用适当的业务规则设置它们的值。

最后,如果您仍想重用自定义的一部分,您可以以允许这种操作的方式扩展 AutoFixture。 Customize<T>()Build<T>() 都使用 IPostprocessComposer<T> 接口来组成内联自定义。您可以编写一个扩展方法来干预该过程并将自定义委托给第三方。

public static class ComposerExtensions
{
    public static IPostprocessComposer<T> Using<T>(this IPostprocessComposer<T> source,IPartialPostprocessComposer<T> composer)
    {
        return composer.Compose(source);
    }
}

现在假设第三方看起来像这样。

public class MyClassPartialComposer : IPartialPostprocessComposer<MyClass>
{
    public IPostprocessComposer<MyClass> Compose(IPostprocessComposer<MyClass> source)
    {
        return source
            .Without(x => x.Cars)
            .Without(x => x.Boats);
    }
}

您的自定义可能如下所示。

var actual = fixture.Build<MyClass>()
    .Using(new MyClassPartialComposer())
    .With(x => x.Name,"hello")
    .Create();

通过这种方法,您还可以组成部分内联自定义。

请记住,虽然 AutoFixture 不正式支持最后一种方法,但您必须自己定义扩展方法和部分 Composer 实现。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?