2015-06-12 8 views
6

Ich bin auf der Suche nach einer schnellen Möglichkeit, meine Tabellen Daten zu reinigen, die Integration Tests mit EF.Nachteil der Verwendung der Transaktion dispose mit Entity Framework Integrationstest

Jeder scheint eine Transaktion um seine Testmethode zu wickeln und die Transaktion nach dem Test zu entsorgen.

Auf diese Weise werden die Daten nie in die Tabelle geschrieben.

Dinge wie neue Auto IDs für Inserts funktionieren noch, aber ich frage mich, ob diese Methode wirklich zuverlässig ist im Vergleich zu .commit() der Transaktion.

Gibt es irgendwelche Nachteile diesen Ansatz zu verwenden, die nicht scheint, ein echten Integrationstest zu sein, wie die Datenbank nie berührt wird ...

Oder mit anderen Worten geben es fehlerhafte Szenarien gefragt, die als Ausnahmen nicht Pop mit die Transaktion ohne 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

Der einzige wirkliche Unterschied ist, dass Sie die Nebenläufigkeit nicht testen. Wenn Sie also brauchen (und Sie werden brauchen!), Werden Sie den Beginn Transaktion/Rollback-Ansatz ändern. Auch eine Sicherung wiederherstellen und eine Datenbank löschen sind einige Zeile von Codes am Anfang/Ende des Tests. – bubi

+0

@bubi Wiederherstellung einer Datenbank ist schneller als context.datebase.Create()? – Elisabeth

+0

Wenn Sie Tests mit einer leeren Datenbank starten können, können Sie auch Create() verwenden. Ich weiß nicht, ob es schneller ist, hängt wahrscheinlich von der Anzahl der Tabellen/Felder/Beziehungen/DBMS ab ... Es könnte auch sein, dass einige EF Provider Create() nicht unterstützen. In meinem Fall verwende ich Microsoft Access, um EF zu testen, und der Anbieter unterstützt CodeFirst-Migrationen, unterstützt aber nicht Create() – bubi

Antwort

2

wie die Datenbank nie berührt

Sicherlich ist es berührt. Alles, was innerhalb der Transaktion passiert, passiert in der Datenbank. Identity-Werte und -Sequenzen (falls vorhanden) werden inkrementiert, Trigger ausgelöst, referentielle Constraints überprüft, usw. Das einzige Problem ist, dass es isoliert geschieht und am Ende alles (außer inkrementierten Identitäten und Sequenzen) zurückgesetzt wird.

Gibt es Nachteile bei der Verwendung dieses Ansatzes?

Nicht wirklich. Ich verwende diesen Ansatz ausführlich in meinem eigenen Code und es hat große Vorteile. Grüne Tests geben ein sehr hohes Maß an Sicherheit. Ich werde mich nie sicher fühlen mit "echten" Unit Test mit gespotteten Kontexten und DbSet 's (obwohl ich Unit-Test für viele andere Dinge verwenden).

Aber es gibt einige Einschränkungen, die Sie beachten sollten.

  • Identitäts-/Sequenzwerte sind nicht deterministisch, daher können Sie sie nicht bestätigen. Wie gesagt, diese Werte werden nicht zurückgesetzt. Wenn Sie in diesem Bereich wirklich Bestätigungen benötigen, können Sie die Identitäten/Sequenzen nach jedem Test zurücksetzen.
  • Wir können nie Concurrency-Probleme mit diesem Ansatz testen.
  • Sie können keine Verbindung zu einer anderen Datenbank oder sogar zu derselben Datenbank herstellen, wenn sich die Verbindungszeichenfolge im geringsten Detail unterscheidet (z. B. ein anderer Anwendungsname oder eine andere MARS-Einstellung), ohne dass DTC eintritt. In der Anwendung Code wäre dies möglich, weil dort diese verschiedenen Anrufe nicht in eine TransactionScope gewickelt werden würde. Vielleicht können nicht alle Anwendungspfade auf diese Weise einfach getestet werden.
  • Entwickler sollten ihre eigene Kopie der Testdatenbank verwenden. Wenn mehrere Entwickler (und möglicherweise ein Build-Server) Tests für dieselbe Datenbank ausführen, können sie sich gegenseitig blockieren.
+0

Dann fühlte ich mich in die Identität nicht zurückgesetzt Trap. Meine Tests funktionierten jeweils für sich selbst, aber wenn ich sie zusammen lief, bekam ich Concurrency-Fehler wegen falscher ID. Ich brauche jeden Test einen neuen Start, sonst hätte mein Test mehrere Annahmen, die niemand erraten kann, das wäre eine schlechte Abhängigkeit. So können mehrere Benutzer dort Sachen nicht festmachen UND die Tests sicher ohne Deadlock laufen lassen? Aber das ist ein typisches Szenario, wenn Sie mich fragen. Concurrency spielt in dieser Anwendung keine Rolle. – Elisabeth

+0

Aufgrund der Isolationsstufe des TransactionScope und der relativ langen Tests können Deadlocks auftreten. Normalerweise würde das nicht so schnell passieren. Ein weiterer Vorteil jedes Entwicklers mit seiner eigenen Datenbank besteht darin, dass er mit neuem db-Inhalt experimentieren kann, ohne andere zu belästigen. Wenn Sie Identitätswerte benötigen (die ich nicht empfehle, verwenden Sie die natürlichen Schlüssel), müssen Sie nach jedem Test DBCC CHECKIDENT (neu formatiert) ausführen. –

+0

Oh die natürlichen Schlüssel vs Ersatzschlüssel Diskussion ist so alt wie die Menschheit ;-) – Elisabeth

Verwandte Themen