2013-03-29 209 views
11

我們有用於存儲的實體框架的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)在不重要的.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這是不正確的地方做到這一點。任何其他想法?

回答

20

瞭解多一點馬克的博客(this particularly)我發現這樣做我想:

/// <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()); 

並去創建你的複雜模型。

享受!

+0

保存當天。但是,至少在美國,Customisations拼寫爲Customizations。 :) –

+5

我知道,討厭的z進入所有* sations。在英國它拼寫正確,與「s」 - ))) – trailmax

+0

這是一個夢幻般的解決方案。我能夠將課程放到我的項目中,並立即用於Moq。很棒的工作! – Halcyon

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.Bar getter將使用DynamicProxy和AutoFixture實時創建Bar的實例並將其分配給該屬性。之後對foo.Bar的調用返回相同的對象。

N.B.定製設置不夠巧妙,無法設置foo.Bar.Foo = foo - 必須在需要時手動完成

+0

太棒了!謝謝! – trailmax

+0

@AlexFoxGill,您的項目不再與最新的AutoFixture 3.3+兼容。當試圖用你的定製運行UT時,會產生一個錯誤,說明程序集不正確。 – Encryption

+0

@Encryption謝謝你讓我知道 – AlexFoxGill