Caso d'uso: disponiamo di un database abbastanza grande (circa 200 tabelle) utilizzato in un sistema di grandi dimensioni (legacy). È implementato come un approccio basato sul database, con un file edmx che definisce l'intero database. Stiamo usando XUnit e Effort per i test automatici. Il problema è che questi test sono molto lenti. Ci vogliono circa 7-8 minuti per eseguire la nostra attuale suite di test, anche se la copertura dei test non è da nessuna parte vicino a ciò che vogliamo che sia.
Ho notato che se creo un sottoinsieme più piccolo del file edmx , rimuovendo alcune tabelle non necessarie, i test vengono eseguiti più rapidamente.
Sto cercando una soluzione in cui per un particolare test, o suite di test, possiamo in qualche modo fare in modo che Effort crei solo il sottoinsieme di tabelle necessarie (penso che in molti casi avremo bisogno di una sola tabella).
Attualmente stiamo configurando la nostra connessione in questo modo:
connection = EntityConnectionFactory.CreateTransient("metadata=res://entities.csdl|res://entities.ssdl|res://entities.msl");
C'è un modo in cui possiamo (ad esempio, eseguendo una trasformazione XML in runtime), fare in modo che Effort crei solo le strutture di dati necessarie per un sottoinsieme di tabelle che definiamo?
Disclaimer : sono il proprietario del progetto Entity Framework Effort
La nostra libreria ha una funzione che consente di creare un punto di ripristino e il rollback ad esso.
Quindi, utilizzando questo trucco, è possibile utilizzare CreateRestorePoint()
solo una volta quando vengono create tutte le tabelle e quindi per ogni test, CreateRestorePoint()
con RollbackToRestorePoint
. (Esistono molti altri modi per farlo funzionare ma immagino che tu capisca il punto)
Senza dubbio renderà il tuo test MOLTO più veloce poiché la tabella non dovrà essere creata ogni volta.
Ecco un esempio:
var conn = Effort.DbConnectionFactory.CreateTransient();
using (var context = new EntityContext(conn))
{
context.EntitySimples.Add(new EntitySimple { ColumnInt = 1 });
context.EntitySimples.Add(new EntitySimple { ColumnInt = 2 });
context.EntitySimples.Add(new EntitySimple { ColumnInt = 3 });
context.SaveChanges();
}
// Create a RestorePoint that will save all current entities in the "Database"
conn.CreateRestorePoint();
// Make any change
using (var context = new EntityContext(conn))
{
context.EntitySimples.RemoveRange(context.EntitySimples);
context.SaveChanges();
}
// Rollback to the restore point to make more tests
conn.RollbackToRestorePoint();
Separare unit test e test di integrazione. Per il test di integrazione è possibile utilizzare Database ed eseguire su ambienti più elevati (per risparmiare tempo) ma su ambienti locali è possibile utilizzare Faker \ Bogus e NBuilder per generare dati di massa per unit test.
https://dzone.com/articles/using-faker-and-nbuilder-to-generate-massive-data
Un'altra opzione è che puoi creare un file di risorse corrispondente ai casi di test unitari https://www.danylkoweb.com/Blog/the-fastest-way-to-mock-a-database-for-unit-testing-B6
Vorrei anche dare un'occhiata alle prestazioni di InMemoryDB vs SqlLite, http://www.mukeshkumar.net/articles/efcore/unit-testing-with-inmemory-provider-and-sqlite-in-memory-database-in- ef-core
Sebbene l'esempio sopra sia per EFCore, anche in EF6 possiamo usare SqlLite https://www.codeproject.com/Tips/1056400/Setting-up-SQLite-and-Entity-Framework-Code-First
Quindi la mia raccomandazione per te è quella di utilizzare sqllite per gli scenari di test di integrazione. Per Unit test puoi andare con sqllite o con Faker \ Bogus e NBuilder.
Spero che sia d'aiuto!