2013-03-29 18 views
11

Abbiamo un progetto MVC4 con Entity Framework per l'archiviazione. Per i nostri test abbiamo recentemente iniziato ad usare l'autofocus ed è davvero fantastico.Ignora proprietà virtuali

Il nostro grafico modelli è molto profondo e di solito la creazione di un oggetto dal AutoFixture crea l'intero grafico: persona -> Team -> Dipartimenti -> Azienda -> Contratti -> .... ecc

Il problema con questo è tempo. La creazione dell'oggetto richiede fino a un secondo. E questo porta a test lenti.

Quello che mi ritrovo a fare un sacco è cose come questa:

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

E questo funziona ed è veloce. Ma questa sovra-specifica rende i test difficili da leggere e, a volte, perdo i dettagli importanti come .With(c => c.PersonId, 42) nell'elenco dei numeri non importanti .Without().

Tutti questi oggetti ignorati sono proprietà di navigazione per Entity Framework e sono tutti virtuali.

C'è un modo globale per dire a AutoFixture di ignorare i membri virtuali?

Ho provato a generare ISpecimentBuilder, ma senza fortuna:

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

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

io non riesco a trovare un modo per rilevare ISpecimenBuilder quell'oggetto stiamo costruendo è un membro virtuale in un'altra classe. Probabilmente ISpecimenBuilder questo non è il posto giusto per farlo. Altre idee?

risposta

20

Leggete un po 'di più sul blog di Mark (this particularly) ho trovato il modo di fare quello che voglio:

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

E si può avvolgere questi in adattamento:

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

Così nel test Basta fare:

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

e andare a creare i tuoi modelli complessi.

Divertiti!

+0

Salvato il giorno. Tuttavia, almeno negli Stati Uniti, Customisations indica le personalizzazioni. :) –

+5

Lo so, fastidioso z entra in tutte le * sazioni. Nel Regno Unito è scritto correttamente, con "s" -))) – trailmax

+0

Questa è una soluzione fantastica. Sono stato in grado di abbandonare le lezioni nel mio progetto e usarle subito con Moq. Lavoro eccellente! – Halcyon

3

Ho avuto lo stesso problema e ho deciso di fare un ulteriore passo avanti e creare una personalizzazione per le proprietà di navigazione a carico lento. Il progetto è su Github e NuGet.

consideri il semplice oggetto grafico sottostante che ha una dipendenza circolare:

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

Con questa personalizzazione, chiamando var foo = fixture.Create<Foo>() creerà un oggetto di tipo Foo. La chiamata al getter foo.Bar utilizza DynamicProxy e AutoFixture per creare immediatamente un'istanza di Bar e assegnarla a tale proprietà. Le chiamate successive a foo.Bar restituiscono lo stesso oggetto.

N.B.la personalizzazione non è abbastanza intelligente da impostare foo.Bar.Foo = foo - questo deve essere fatto manualmente se necessario

+0

È fantastico! Grazie! – trailmax

+0

@AlexFoxGill, il tuo progetto non è più compatibile con l'ultima AutoFixture 3.3+. Quando si tenta di eseguire UT con la propria personalizzazione, viene generato un errore che l'assembly non è corretto. – Encryption

+0

@Crittografia grazie per avermi fatto sapere – AlexFoxGill

Problemi correlati