2009-02-22 6 views
34

Sono codice di test dell'unità scritto contro ADO .NET Entity Framework. Vorrei popolare un database in memoria con le righe e assicurarmi che il mio codice lo recuperi correttamente.Esiste un provider in memoria per Entity Framework?

Posso prendere in giro Entity Framework usando Rhino Mocks, ma ciò non sarebbe sufficiente. Vorrei dire alla domanda quali entità dovrei tornare da me. Ciò non testerebbe né la clausola where né le istruzioni .Include(). Voglio essere sicuro che la mia clausola where corrisponda solo alle righe che intendo, e nessuna altra. Voglio essere sicuro di aver chiesto le entità di cui ho bisogno, e nessuna di quelle che non ho.

Ad esempio:

class CustomerService 
{ 
    ObjectQuery<Customer> _customerSource; 
    public CustomerService(ObjectQuery<Customer> customerSource) 
    { 
     _customerSource = customerSource; 
    } 
    public Customer GetCustomerById(int customerId) 
    { 
     var customers = from c in _customerSource.Include("Order") 
      where c.CustomerID == customerId 
      select c; 
     return customers.FirstOrDefault(); 
    } 
} 

Se io giro l'ObjectQuery per tornare un cliente conosciuto popolato con gli ordini, come faccio a sapere che CustomerService ha il diritto clausola where e Includi? Vorrei piuttosto inserire alcune righe di clienti e alcune righe di ordine, quindi affermare che il cliente giusto è stato selezionato e gli ordini sono compilati.

+1

Come hai finito, ho usato le interfacce per seguire il modello di deposito e il modello di unità di lavoro. Quindi, ho due namespace -> EF e Fake. Con il mio repository Fake, ho appena utilizzato IList per archiviare i miei file e sfruttare Linq per gli oggetti per estrarre i dati. Funziona benissimo :) –

+4

EntityFramework 7 dispone ora del provider InMemoery. Ancora beta come di commento, ma se ti iscrivi al nightly nuget puoi ottenerlo. – ppumkin

risposta

7

Attualmente non esiste un provider in memoria per EF, ma se date un'occhiata a Highway.Data ha un'interfaccia di astrazione di base e un InMemoryDataContext.

Testing Data Access and EF with Highway.Data

+8

Questa non è più la risposta corretta. EF7 ora supporta InMemory ... beh, quando è stato rilasciato in un futuro non troppo lontano. – ppumkin

+3

È in Beta al momento della stesura di questo documento. Cerca EntityFramework.InMemory su NuGet. – HiredMind

+0

Mentre EF7 includerà un provider InMemory ... Sono a conoscenza del fatto che il provider InMemory è molto astratto in quanto imita le caratteristiche comuni di tutti i provider. Dovrai utilizzare qualcosa come il provider EntityFramework.SqlLite per i test unitari che richiedono la convalida di determinati concetti specifici del provider. Ad esempio, non sono stato in grado di verificare vincoli univoci o vincoli di campo obbligatori utilizzando il provider InMemory. Inoltre non puoi convalidare i vincoli relazionali con esso. Maggiori dettagli qui: https://github.com/aspnet/EntityFramework/issues/2166 – Paul

2

non ho familiarità con Entity Framework e la classe ObjectQuery ma se il metodo Include è virtuale si può deridere in questo modo:

// Arrange 
var customerSourceStub = MockRepository.GenerateStub<ObjectQuery<Customer>>(); 
var customers = new Customer[] 
{ 
    // Populate your customers as if they were coming from DB 
}; 
customerSourceStub 
    .Stub(x => x.Include("Order")) 
    .Return(customers); 
var sut = new CustomerService(customerSourceStub); 

// Act 
var actual = sut.GetCustomerById(5); 

// Assert 
Assert.IsNotNull(actual); 
Assert.AreEqual(5, actual.Id); 
+0

Esistono due funzionalità del metodo GetCustomerById: la clausola where e l'inclusione. Se faccio schifo alla fonte del cliente per restituire un cliente conosciuto, non sto testando nessuno dei due. –

+0

Se si prende in giro il metodo Include, non si restituisce un cliente noto ma un elenco di clienti noti, quindi è possibile testare la clausola where per vedere se trova il cliente tramite il suo id. Per quanto riguarda il metodo Include, si verifica anche che si chiami con l'argomento corretto: Ordine –

6

sì, c'è almeno un tale fornitore - SQLite. L'ho usato un po 'e funziona. Inoltre puoi provare SQL Server Compact. È un database integrato e ha anche fornitori di EF.
Modifica:
SQLite supporta i database in memoria (link1). Tutto ciò che serve è specificare una stringa di connessione come: "Data Source =: memory:; Version = 3; New = True;". Se è necessario in un esempio, è possibile consultare SharpArchitecture.

+0

Potrei usare un database incorporato (in-process), ma preferirei andare completamente in memoria. Mi piacerebbe definire le mie tabelle e compilare alcune righe completamente in codice, e non scrivere mai nulla su disco. Quindi potrei fare in modo che il test dell'unità verifichi che il mio CustomerService interroghi correttamente i dati. –

+0

SQLite supporta i database in memoria, vedere la risposta modificata. – zihotki

+0

Preferirei un db reale eseguito all'interno della memoria perché la cosa più importante da testare è le relazioni e i vincoli di db e si ha scarso supporto per quello nel codice. Quello che mi infastidisce è che questa è una logica applicativa e dovrebbe essere rappresentata nel tuo modello e non nel database. – terjetyl

10

Un approccio migliore potrebbe essere quello di utilizzare il modello di repository per incapsulare il codice EF. Quando collaudi i tuoi servizi puoi usare finte o falsi. Quando testi i tuoi repository, vorrai colpire il vero DB per assicurarti di ottenere i risultati che ti aspetti.

+0

Se si prende in giro il repository per restituire un determinato cliente, ciò non verifica la specifica. Voglio includere la specifica nel test dell'unità, e non aspettare fino a quando non sto usando un vero DB. –

+1

Lol .. E in che modo le query LINQ2Entities possono essere testate con pattern Repository? Non c'è modo di farlo perché queste query generano query SQL e abbiamo bisogno di testarle anche nel database. – zihotki

+1

Sto accettando questa risposta perché è la cosa più vicina a ciò che ho effettivamente fatto. Ho creato interfacce nella forma del pattern di repository, quindi implementato sia un adattatore EF che un harness di test in memoria. Non verifica il DB, ma verifica le mie specifiche. –

1

Si potrebbe provare SQL Server Compact ma ha alcune limitazioni abbastanza selvaggio:

  • SQL Server Compact non supporta le espressioni SKIP nelle query di paging quando viene utilizzato con Entity Framework
  • SQL Server Compact non supporta entità con chiavi o valori generati dal server quando viene utilizzato con Entity Framework
  • No outer join, fascicolazione, modulo su carri, gli aggregati
16

Un provider InMemory è incluso nel EF7 (pre-release).

È possibile utilizzare lo NuGet package o leggere su di esso nello EF repo su GitHub (view source).

+4

Mentre questo è vero, EF7 è ancora molto pre-release e Microsoft ha dichiarato che EF7 NON è semplicemente il prossimo versione da EF6; ecco perché l'hanno ribattezzato EF Core 1.0 –

+0

Il nostro team ha deciso di non toccare EF7 fino a quando non saranno implementati i tipi complessi e TPT. EF7 è troppo grezzo. – Shimmy

0

In EF Core ci sono due opzioni principali per fare questo:

  1. SQLite in-memory mode consente di scrivere i test efficaci nei confronti di un fornitore che si comporta come un database relazionale.
  2. The InMemory provider è un fornitore leggero che ha dipendenze minime, ma non sempre si comportano come un database relazionale

Sto usando SQLite e supporta tutte le query, che ho bisogno di fare con il database di produzione Azure SQL.

Problemi correlati