2013-03-29 21 views
11

Mamy projekt MVC4 z Entity Framework do przechowywania. Na potrzeby naszych testów niedawno zaczęliśmy używać Autofixture i jest naprawdę świetny.Ignoruj ​​właściwości wirtualne

Nasze modele wykres jest bardzo głęboka i zwykle tworząc jeden obiekt przez AutoFixture tworzy cały wykres: Person -> Team -> Wydziały -> Firma -> Usługi -> .... itp

Problem z tym jest czas. Tworzenie obiektów zajmuje do jednej sekundy. A to prowadzi do powolnych testów.

Co ja znajduję się robi wiele jest rzeczy tak:

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

I to działa i jest szybki. Ale ta nadmierna specyfikacja sprawia, że ​​testy są trudne do odczytania i czasami tracę ważne informacje, takie jak .With(c => c.PersonId, 42) na liście nieistotnych .Without().

Wszystkie te ignorowane obiekty są właściwościami nawigacyjnymi dla Entity Framework i wszystkie są wirtualne.

Czy istnieje ogólnoświatowy sposób powiadamiania AutoFixture o ignorowaniu wirtualnych członków?

Próbowałem tworzenia ISpecimentBuilder, ale bez powodzenia:

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

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

I nie wydają się znaleźć sposób, aby wykryć w ISpecimenBuilder tego obiektu budujemy jest członkiem wirtualny w innej klasie. Prawdopodobnie ISpecimenBuilder to nie jest właściwe miejsce, aby to zrobić. Jakieś inne pomysły?

Odpowiedz

20

Czytaj trochę więcej na blogu Marka (this particularly) znalazłem drogę do tego, co chcę:

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

I można zawinąć je do personalizacji:

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

Więc w teście po prostu wykonaj:

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

i przejdź do tworzenia złożonych modeli.

Ciesz się!

+0

Uratowałem dzień. Jednak przynajmniej w Stanach Zjednoczonych w Customisations pisane są Dostosowania. :) –

+5

Wiem, pesky z dostaje się do wszystkich * sations. W Wielkiej Brytanii jest napisane poprawnie, z "s" -))) – trailmax

+0

To fantastyczne rozwiązanie. Udało mi się przenieść zajęcia do mojego projektu i od razu wykorzystać je z Moq. Świetna robota! – Halcyon

3

Miałem ten sam problem i zdecydowałem się pójść o krok dalej i stworzyć dostosowywanie do właściwości nawigacyjnych leniwego ładowania. Projekt jest dostępny pod numerami Github i NuGet.

Rozważmy prosty wykres obiektu, poniżej której ma kołową zależność:

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

Z tej personalizacji, nazywając var foo = fixture.Create<Foo>() stworzy obiekt typu Foo. Wywołanie pobierającego foo.Bar spowoduje użycie DynamicProxy i AutoFixture do utworzenia w locie instancji Bar i przypisania jej do tej właściwości. Kolejne wywołania do foo.Bar zwracają ten sam obiekt.

N.B.dostosowywanie nie jest wystarczająco inteligentne, aby ustawić foo.Bar.Foo = foo - trzeba to zrobić ręcznie, jeśli to konieczne

+0

To jest fantastyczne! Dziękuję Ci! – trailmax

+0

@AlexFoxGill, twój projekt nie jest już kompatybilny z najnowszą wersją AutoFixture 3.3+. Podczas próby uruchomienia UT z dostosowaniem generowany jest błąd, który nie jest poprawny. – Encryption

+0

@Encryption dzięki za poinformowanie mnie – AlexFoxGill

Powiązane problemy