Irgendwo in Ihrer Codebasis befindet sich eine Codezeile, die die eigentliche Aktion zum Herstellen einer Verbindung mit der entfernten Datenbank ausführt. Diese Codezeile ist 9-mal in 10 ein Aufruf einer "eingebauten" Methode, die von den für Ihre Sprache und Umgebung spezifischen Laufzeitbibliotheken bereitgestellt wird. Als solches ist es nicht "Ihr" Code und Sie müssen ihn nicht testen. Für die Zwecke eines Komponententests können Sie darauf vertrauen, dass dieser Methodenaufruf ordnungsgemäß ausgeführt wird. Was Sie in Ihrer Unit-Testsuite noch testen können und sollten, sind Dinge wie die Sicherstellung, dass die Parameter, die für diesen Aufruf verwendet werden, Ihren Erwartungen entsprechen, z. B. die Richtigkeit der Verbindungszeichenfolge oder die SQL-Anweisung oder Name der gespeicherten Prozedur.
Dies ist einer der Gründe für die Einschränkung, dass Komponententests ihre Laufzeit- "Sandbox" nicht verlassen dürfen und vom externen Status abhängig sind. Es ist eigentlich ganz praktisch; Mit einem Komponententest soll überprüft werden, ob sich der von Ihnen geschriebene Code (oder der Code , der gerade in TDD geschrieben wird) so verhält, wie Sie es sich vorgestellt haben. Code, den Sie nicht geschrieben haben, wie z. B. die Bibliothek, mit der Sie Ihre Datenbankoperationen ausführen, sollte aus dem einfachen Grund, dass Sie ihn nicht geschrieben haben, nicht Bestandteil eines Komponententests sein.
In Ihrer Integrationstestsuite werden diese Einschränkungen gelockert. Jetzt Sie könnenDesigntests, die die Datenbank berühren, um sicherzustellen, dass der Code, den Sie geschrieben haben, gut mit Code zusammenarbeitet, den Sie nicht geschrieben haben. Diese beiden Testsuiten sollten jedoch getrennt bleiben, da Ihre Komponententestsuite umso effektiver ist, je schneller sie ausgeführt wird (sodass Sie schnell überprüfen können, ob alle Aussagen der Entwickler zu ihrem Code noch gültig sind) ist aufgrund der zusätzlichen Abhängigkeit von externen Ressourcen um Größenordnungen langsamer. Lassen Sie den Build-Bot alle paar Stunden Ihre vollständige Integrationssuite ausführen und die Tests ausführen, mit denen externe Ressourcen gesperrt werden, damit die Entwickler sich nicht gegenseitig auf die Nerven gehen, indem sie dieselben Tests lokal ausführen. Und wenn der Build kaputt geht, was dann? Es wird viel mehr Wert darauf gelegt, dass der Build-Bot niemals einen Build verfehlt, als es wahrscheinlich sein sollte.
Wie genau Sie sich nun daran halten können, hängt von Ihrer genauen Strategie ab, wie Sie eine Verbindung zur Datenbank herstellen und diese abfragen. In vielen Fällen, in denen Sie das "Bare-Bones" -Datenzugriffsframework verwenden müssen, z. B. bei den ADO.NET-Objekten SqlConnection und SqlStatement, kann eine von Ihnen entwickelte Methode aus integrierten Methodenaufrufen und anderem Code bestehen, der von a abhängig ist Datenbankverbindung. Das Beste, was Sie in dieser Situation tun können, ist, die gesamte Funktion zu verspotten und Ihren Integrationstestsuiten zu vertrauen. Es hängt auch davon ab, wie weit Sie bereit sind, Ihre Klassen so zu entwerfen, dass bestimmte Codezeilen zu Testzwecken ersetzt werden können (z. B. Tobis Vorschlag für das Template-Methodenmuster, das gut ist, weil es "partielle Verspottungen" ermöglicht).
Wenn sich Ihr Datenpersistenzmodell auf Code in Ihrer Datenschicht stützt (z. B. Trigger, gespeicherte Prozesse usw.), gibt es einfach keine andere Möglichkeit, Code auszuüben, den Sie selbst schreiben, als Tests zu entwickeln, die entweder in der Datenschicht ablaufen oder die Datenschicht durchqueren Grenze zwischen Ihrer Anwendungslaufzeit und dem DBMS. Ein Purist würde sagen, dass dieses Muster aus diesem Grund zugunsten eines ORM vermieden werden sollte. Ich glaube nicht, dass ich so weit kommen würde. Selbst im Zeitalter sprachintegrierter Abfragen und anderer vom Compiler überprüfter, domänenabhängiger Persistenzvorgänge sehe ich den Wert darin, die Datenbank nur auf die Vorgänge zu beschränken, die über gespeicherte Prozeduren verfügbar gemacht werden, und natürlich müssen solche gespeicherten Prozeduren automatisiert überprüft werden Tests. Aber solche Tests sind nicht Einheit Tests. Sie sind Integration Tests.
Wenn Sie ein Problem mit dieser Unterscheidung haben, liegt dies in der Regel an der hohen Bedeutung einer vollständigen "Codeabdeckung", auch bekannt als "Einheitentestabdeckung". Sie möchten sicherstellen, dass jede Codezeile von einem Komponententest abgedeckt wird. Ein edles Ziel im Gesicht, aber ich sage Hogwash; Diese Mentalität eignet sich für Anti-Patterns, die weit über diesen speziellen Fall hinausreichen, wie das Schreiben von aussagefreien Tests, die ausgeführt werden, aber keine Übungen ausführendein Code. Diese Arten von End-Runs, die ausschließlich der Deckung dienen, sind schädlicher als die Lockerung Ihrer Mindestdeckung. Wenn Sie sicherstellen möchten, dass jede Zeile Ihrer Codebasis durch einen automatisierten Test ausgeführt wird, ist dies ganz einfach. Berücksichtigen Sie beim Berechnen von Kennzahlen zur Codeabdeckung die Integrationstests. Sie könnten sogar noch einen Schritt weiter gehen und diese umstrittenen "Itino" -Tests ("Integration nur in Namen") isolieren, und zwischen Ihrer Unit-Testsuite und dieser Unterkategorie von Integrationstests (die immer noch relativ schnell ablaufen sollten) sollten Sie verdammt sein Nahezu vollständige Abdeckung.