13

我们有用于存储的实体框架的 MVC4 项目。对于我们的测试,我们最近开始使用 Autofixture,它真的很棒。

我们的模型图非常深,通常通过 AutoFixture 创建一个对象会创建整个图:人员 -> 团队 -> 部门 -> 公司 -> 合同 -> ....等。

这个问题是时间。对象创建最多需要一秒钟。这会导致测试缓慢。

我发现自己经常做的是这样的事情:

        var contract = fixture.Build<PersonContract>()
            .Without(c => c.Person)
            .Without(c => c.PersonContractTemplate)
            .Without(c => c.Occupation)
            .Without(c => c.EmploymentCompany)
            .Create<PersonContract>();

这很有效,而且速度很快。但是这种过度规范使测试难以阅读,有时我会丢失一些重要的细节,比如.With(c => c.PersonId, 42)在 unimportant 列表中.Without()

所有这些被忽略的对象都是 Entity Framework 的导航属性,并且都是虚拟的。

有没有一种全局方法来告诉 AutoFixture 忽略虚拟成员?

我尝试过创建ISpecimentBuilder,但没有运气:

public class IgnoreVirtualMembers : ISpecimenBuilder
{
    public object Create(object request, ISpecimenContext context)
    {

        if (request.GetType().IsVirtual // ?? this does not exist )
        {
             return null;
        }
    }
}

我似乎无法找到一种方法ISpecimenBuilder来检测我们正在构建的对象是另一个类中的虚拟成员。可能ISpecimenBuilder这不是执行此操作的正确位置。还有其他想法吗?

4

2 回答 2

23

在马克的博客上阅读更多内容(特别是这个)我找到了做我想做的事情的方法:

/// <summary>
/// Customisation to ignore the virtual members in the class - helps ignoring the navigational 
/// properties and makes it quicker to generate objects when you don't care about these
/// </summary>
public class IgnoreVirtualMembers : ISpecimenBuilder
{
    public object Create(object request, ISpecimenContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }

        var pi = request as PropertyInfo;
        if (pi == null)
        {
            return new NoSpecimen(request);
        }

        if (pi.GetGetMethod().IsVirtual)
        {
            return null;
        }
        return new NoSpecimen(request);
    }
}

您可以将这些包装到自定义中:

public class IgnoreVirtualMembersCustomisation : ICustomization
{
    public void Customize(IFixture fixture)
    {
        fixture.Customizations.Add(new IgnoreVirtualMembers());
    }
}

因此,在您的测试中,您只需执行以下操作:

var fixture = new Fixture().Customize(new IgnoreVirtualMembersCustomisation());

然后去创建你的复杂模型。

享受!

于 2013-03-29T16:34:18.560 回答
3

我遇到了同样的问题,并决定更进一步,为延迟加载导航属性创建自定义。该项目位于GithubNuGet上。

考虑下面的简单对象图,它具有循环依赖:

class Foo
{
    public int Id { get; set; }
    public int BarId { get; set; }
    public virtual Bar Bar { get; set; }
}

class Bar
{
    public int Id { get; set; }
    public int FooId { get; set; }
    public virtual Foo Foo { get; set; }
}

通过这种定制,调用var foo = fixture.Create<Foo>()将创建一个类型为 的对象Foo。调用foo.Bargetter 将使用 DynamicProxy 和 AutoFixture 动态创建一个实例Bar并将其分配给该属性。后续调用foo.Bar返回相同的对象。

注意自定义设置不够智能foo.Bar.Foo = foo- 如果需要,必须手动完成

于 2014-05-24T08:50:53.853 回答