2015-06-12 10 views
6

Sto cercando un modo rapido per pulire i dati delle tabelle eseguendo test di integrazione con EF.Il lato negativo dell'utilizzo della transazione viene eliminato con il test di integrazione del framework di entità

Ognuno sembra avvolgere una transazione attorno al suo metodo di prova e smaltire la transazione dopo il test.

In questo modo i dati non vengono mai scritti sulla tabella.

Le cose come i nuovi ID auto per gli inserti sono ancora funzionanti, ma mi chiedo se questo metodo sia veramente affidabile rispetto a .commit() della transazione.

Ci sono aspetti negativi di utilizzo di questo approccio che sembrano non essere un vero e proprio test di integrazione come il database non viene mai toccato ...

o chiesto, in altre parole sono lì scenari difettosi che non compaiono come eccezioni utilizzando la transazione senza commit()?

UPDATE

public abstract class IntegrationTestsBase 
    { 
     protected TransactionScope TransactionScope; 

     public abstract void TestSetup(); 
     protected void InitTestSetupOnTable(string tableName) 
     { 
      TransactionScope = new TransactionScope(); 

      using (var context = new TGBContext()) 
      { 
       var cmdCommand = string.Format("DBCC CHECKIDENT ({0}, RESEED, 1)", tableName); 
       context.Database.ExecuteSqlCommand(cmdCommand); 
       context.SaveChanges(); 
      } 
     } 

     [TestCleanup] 
     public void TestCleanup() 
     { 
      TransactionScope.Dispose(); 
     } 
    } 

[TestClass] 
public class MyTests : IntegrationTestsBase 
{ 
     [TestInitialize] 
     public override void TestSetup() 
     { 
      base.InitTestSetupOnTable("MyTableName");   
     } 
} 
+0

L'unica vera differenza è che non si verifica la concorrenza. Quindi quando avrai bisogno (e ne avrai bisogno!) Cambierai l'approccio di transazione/rollback iniziale. Inoltre, ripristinare un backup e rilasciare un database sono poche righe di codice all'inizio/fine del test. – bubi

+0

@bubi Ripristinare un database è più veloce di context.datebase.Create()? – Elisabeth

+0

Se è possibile avviare test con un database vuoto, è possibile utilizzare anche Create(). Non so se è più veloce probabilmente dipende dal numero di tabelle/campi/relazioni/DBMS ... Inoltre, potrebbe essere che alcuni provider EF non supportano Create(). Nel mio caso, utilizzo Microsoft Access per testare EF e il provider supporta le migrazioni codefirst ma non supporta Create() – bubi

risposta

2

come il database non è mai toccato

Sicuramente è toccato. Tutto ciò che accade all'interno della transazione avviene nel database. I valori di identità e le sequenze (se presenti) sono incrementati, innesca il fuoco, i vincoli referenziali sono controllati, ecc. Ecc. L'unica cosa è che accade in isolamento e alla fine tutto (eccetto identità e sequenze incrementate) viene ripristinato.

Ci sono dei lati negativi nell'usare questo approccio?

Non proprio. Uso estesamente questo approccio nel mio codice e ha grandi meriti. I test verdi offrono un livello molto alto di garanzia. Non mi sentirò mai al sicuro con il test dell'unità "reale" usando contesti simulati e lo DbSet (anche se uso il test unitario per molte altre cose).

Ma ci sono alcune restrizioni di cui dovresti essere a conoscenza.

  • I valori di identità/sequenza non sono deterministici, quindi non è possibile asserirli. Come ho detto, questi valori non verranno ripristinati. Se hai davvero bisogno di asserzioni in quest'area, puoi resettare identità/sequenze dopo ogni test.
  • Non possiamo mai testare problemi di concorrenza con questo approccio.
  • Non è possibile aprire una connessione a un altro database o anche allo stesso database se la sua stringa di connessione differisce nel minimo dettaglio (ad esempio un nome di applicazione diverso o un'impostazione MARS diversa), senza kick-in. codice questo sarebbe possibile perché queste chiamate diverse non verrebbero incluse in un TransactionScope. Quindi forse non tutti i percorsi applicativi possono essere facilmente testati in questo modo.
  • Gli sviluppatori devono utilizzare la propria copia del database di test. Se più sviluppatori (e forse un server di build) eseguono test sullo stesso database, potrebbero bloccarsi a vicenda.
+0

Poi ho sentito l'identità non resettare trap. I miei test hanno funzionato ognuno per conto suo ma quando li ho eseguiti insieme ho avuto errori di concorrenza a causa di un ID errato. Devo fare in modo che ogni test abbia una nuova ID di partenza, altrimenti i miei test multipli supporteranno che nessuno potrebbe indovinare, sarebbe una pessima dipendenza. Quindi un utente multiplo non può commettere cose lì ed eseguire i test in sicurezza senza deadlock? Ma questo è uno scenario tipico se me lo chiedi. La concorrenza non ha alcun ruolo in questa applicazione. – Elisabeth

+0

È a causa del livello di isolamento di TransactionScope e dei test eseguiti relativamente a lungo che possono verificarsi deadlock. Normalmente ciò non accadrebbe così rapidamente. Un altro vantaggio di ogni dev che ha il proprio database è che possono sperimentare nuovi contenuti db senza disturbare gli altri. Se hai bisogno di valori di identità (che non consiglio, usa le chiavi naturali) devi eseguire DBCC CHECKIDENT (reseeding) dopo ogni test. –

+0

Oh le chiavi naturali vs la discussione delle chiavi surrogate è vecchia quanto l'umanità ;-) – Elisabeth

Problemi correlati