Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Unittests für DB-Zugriffe (https://www.delphipraxis.net/185504-unittests-fuer-db-zugriffe.html)

hoika 17. Jun 2015 12:52

Datenbank: Firebird • Version: 2 • Zugriff über: IBDAC

Unittests für DB-Zugriffe
 
Hallo,

in einem Dokument zu Unittests habe ich gelesen,
dass DB-Zugriffe in Unit-Tests nichts zu suchen haben, weil sie die Testdauer extrem verlangsamen.

Nur wie teste ich denn jetzt die Korrektheit meiner DB-Zugriffe ?

Sollte man vielleicht 2 Unit-Test-Projekte machen, eines für die DB-Zugriffe und eines für alle anderen?

Wie geht ihr denn dabei vor?


Danke


Heiko

BUG 17. Jun 2015 13:06

AW: Unittests für DB-Zugriffe
 
Zitat:

Zitat von hoika (Beitrag 1305418)
Nur wie teste ich denn jetzt die Korrektheit meiner DB-Zugriffe ?
Sollte man vielleicht 2 Unit-Test-Projekte machen, eines für die DB-Zugriffe und eines für alle anderen?

Im Prinzip: Nicht alle Test müssen Unit-Test sein. Es gibt vermutlich Teile deines DB-Zugriffes für die Unit-Test sinnvoll sind (zB. Query-Generatoren). Die Interaktion mit der DB sind vielleicht eher was für Intergrationstests.

hoika 17. Jun 2015 13:49

AW: Unittests für DB-Zugriffe
 
Hallo,
Integrationstest, äh, eher nein.

Genauer gesagt, mische ich das meistens ;)

Im Moment versuche ich gerade, wirklich einen Einzeltest,
also eine einzige Query (OK, ist eine Service-Methode, der die Query über Filterkriterien zusammenbaut), zu testen.
Dazu will ich konstante Testbedingungen, habe also eine DB mit einem bestimmten Aufbau und Inhalt
und kann meinen Service mit beliebigen Filterkriterien testen.

Ist also doch ein Unittest.

Man merkt es aber schon, wenn dieser Zeitcase mitläuft, dauert es eine Weile (DB-Connect),
verglichen mit einem Nicht-DB-Testcase.


Heiko

Bernhard Geyer 17. Jun 2015 13:51

AW: Unittests für DB-Zugriffe
 
WEnn du Unittests mit z.B. Jenkins nach jedem Checkin laufen lässt, so lasse die DB-Unittest z.B. nur alle Tage laufen wenn sonst die Laufzeit zu hoch wäre.

Uwe Raabe 17. Jun 2015 14:33

AW: Unittests für DB-Zugriffe
 
Kannst du für den DB-Test nicht eine In-Memory-Datenbank nehmen (z.B. FireDAC MemTables mit LocalSQL) oder wenigstens eine Embedded-Lösung? Dann kannst du die Datenbank direkt im Test-Setup aufbauen. Das ist leichter zu pflegen wenn sich mal was an der Logik oder am Test ändert.

hoika 17. Jun 2015 15:25

AW: Unittests für DB-Zugriffe
 
Hallo,

es geht mir gerade um das "Mach es so, wie es beim Kunden läuft?".
Aber mit einer Embedded-DB ist eine gute Idee.

Ich denke, ich mache eine Extra-DB-Suite als Wrapper und packe dort meine DB-TestCases rein,
dann kann ich die global aus- und einknippsen.

Danke


Heiko

Dejan Vu 17. Jun 2015 19:10

AW: Unittests für DB-Zugriffe
 
Ein Unittest mit DB-Zugriff geht über Systemgrenzen hinweg und ist somit kein Unittest. Soviel erst einmal zur Definition.

Ändert natürlich nichts an der Tatsache, das Du den DB-Zugriff testen. Was willst du denn testen? Ob eine Query das erwartete Ergebnis liefert? Ob Tabellen vorhanden sind? Ob die DB vorhanden ist?
Was ist denn bei einer Query das erwartete Ergebnis? Müsste die Datenbank nicht immer die gleiche sein, wenn Du die Tests neu startest?

Fragen über Fragen.

Also, erklär mal, was Du genau willst.

Sir Rufo 17. Jun 2015 20:20

AW: Unittests für DB-Zugriffe
 
@Dejan Vu

Deine Fragen sind vom TE eigentlich schon beantwortet worden ... (siehe #3)

Stevie 17. Jun 2015 21:58

AW: Unittests für DB-Zugriffe
 
Zitat:

Zitat von hoika (Beitrag 1305434)
... DB ...

Ist also doch ein Unittest.

Zitat:

Zitat von Dejan Vu (Beitrag 1305471)
Ein Unittest mit DB-Zugriff geht über Systemgrenzen hinweg und ist somit kein Unittest. Soviel erst einmal zur Definition.

Exakt. Ein Unittest ist per Definition isoliert.

Zitat:

Zitat von Wikipedia
Modultests testen ein Modul isoliert, d. h. weitgehend ohne Interaktion mit anderen Modulen. Deshalb müssen oder können bei Modultests andere Module beziehungsweise externe Komponenten wie etwa eine Datenbank, Dateien, Backendsysteme oder Unterprogramme durch Hilfsobjekte simuliert werden, soweit das zu testende Modul (Prüfling oder Testobjekt) diese benötigt. Vollständige Tests mit allen Komponenten in ihrer Originalversion sollten in den nachfolgenden Integrations- und Systemtests durchgeführt werden.


hoika 18. Jun 2015 05:33

AW: Unittests für DB-Zugriffe
 
Hallo,
dann ist das halt kein Unittest :)
Ich will ja gerade den DB-Zugriff selbst testen.
Dahinter kommen in anderen Methoden des Testcases noch die eigentlichen Detailtssts.

Und ja, genau dafür baue ich mir eine DB, die genau die Tabellen und Inhalte hat, die ich für meinen Test erwarte.
Zusätzlich enthält diese DB natürlich noch andere Daten, die beim Where der SQL-Abfeage ausgefiltert werden.

Danke

Heiko

Dejan Vu 18. Jun 2015 07:26

AW: Unittests für DB-Zugriffe
 
Du willst hier also den DB-Zugriff und die Query testen? Oder deinen dynamischen Querybuilder?

Was willst Du am Zugriff testen? Das ADO funktioniert und du den Connectionstring richtig geschrieben hast? Nun ja, das geht auch im einem einfachen Vergleich.

Den Querybuilder kannst du durch einfache Unittests testen. Für jede Option ein Test. Ist das zu kompliziert? In kleinere Klassen aufteilen.

Stimmen die Feldnamen der erzeugten Query mit den aktuellen Tabellennamen überein? Dann kannst du die Query einfach gegen die DB laufen lassen. Das ist zwar kein UT, stellt aber trotzdem sicher, das die Query ausführbar ist. Allerdings: Welche Query? Alle möglichen? Eine, von der Du meinst, das sie alle Feldnamen enthält? Wie stellst Du das sicher?

Dann lieber die Feldnamen direkt verifizieren, d.h. banale UT für die Felder schreiben. Bekommt der QB die Feldnamen per Schema aus der DB? Dann teste das.

Uwe Raabe 18. Jun 2015 08:04

AW: Unittests für DB-Zugriffe
 
Zitat:

Zitat von hoika (Beitrag 1305494)
dann ist das halt kein Unittest :)

Da hast du vollkommen Recht! Es Nicht-Unittest ist allemal besser als gar kein Test. Solange er das testet was du willst, kann dir eigentlich egal sein, ob es formell ein Unittest ist oder nicht. Ob er dann zusammen mit den anderen (echten) Unittests ausgeführt wird oder separat ist auch völlig Banane, solange er eben auch ausgeführt wird.

Ich habe auch bestimmt eine große Zahl an Tests unter der Rubrik "Unittests" laufen, die streng genommen gar keine sind. Trotzdem erfüllen sie ihren Zweck und ich möchte nicht mehr darauf verzichten. In manchen gewachsenen Projekten ist das manchmal die einzige Möglichkeit, eine brauchbare Testabdeckung herzustellen. Wenn man dafür dann die Infrastruktur der Unittests (z.B. DUnit) nutzt, ist das auch nicht mehr als Pragmatismus. Mögen die Dogmatiker hier jetzt auch hyperventilieren - das geht mir vollkommen am
Delphi-Quellcode:
end.
vorbei :wink:

JasonDX 18. Jun 2015 08:25

AW: Unittests für DB-Zugriffe
 
Wenn ich Tests habe, die bei jeder Codeänderung laufen müssen, und dafür 2 Stunden brauchen weil sie ein externes System ankarren, dann sind diese Tests eine unnötige Behinderung für den Entwickler.
Integrationstests sind wichtig, und genau diese sollten die Schnittstelle zwischen DB und Logik testen. Diese Schnittstelle wird aber in Unittests rausgemockt - damit man seinen Code ändern kann, ohne die Integrationstests laufen lassen zu müssen.

Uwe Raabe 18. Jun 2015 09:05

AW: Unittests für DB-Zugriffe
 
Zitat:

Zitat von JasonDX (Beitrag 1305506)
Wenn ich Tests habe, die bei jeder Codeänderung laufen müssen, und dafür 2 Stunden brauchen weil sie ein externes System ankarren, dann sind diese Tests eine unnötige Behinderung für den Entwickler.
Integrationstests sind wichtig, und genau diese sollten die Schnittstelle zwischen DB und Logik testen. Diese Schnittstelle wird aber in Unittests rausgemockt - damit man seinen Code ändern kann, ohne die Integrationstests laufen lassen zu müssen.

Das Problem mit der Laufzeit gilt aber auch für reine Unittests (z.B. Berechne alle Primzahlen von 1..n mit n ausreichend groß). Deswegen lässt man solche Tests ja auch nicht ständig mitlaufen. Ich bin mir nur nicht sicher, ob die Definition eines Unittests von der Laufzeit abhängt. Oder gibt es irgendwo eine Definition, die Unittests generell als kurz (was auch immer das sein mag) festlegt?

Es ist natürlich schon sinnvoll, kurze Tests spätestens beim Commit oder sogar "ständig" laufen zu lassen (Stichwort TestInsight) und längere Tests dem CI-System zu überlassen. Wie man diese Tests dann im einzelnen nennt, spielt eigentlich eine untergeordnete Rolle.

Was mich bei einem solchen DB-Test eher stören würde, ist die schlechte Portierbarkeit wenn er Zugriff auf einen DB-Server mit einer definierten Datenbank haben muss. Was ist wenn der DB-Server nicht erreichbar ist? Wenn keine (passenden) DB-Treiber installiert sind? Wenn gleichzeitig ein anderer Prozess diese Datenbank manipuliert?

Man muss auch sehen, was eigentlich getestet werden soll. Geht es vielleicht nur darum, ob die richtige SQL-Anweisung erzeugt wird? Das ließe sich natürlich auch ohne DB validieren.

JasonDX 18. Jun 2015 10:18

AW: Unittests für DB-Zugriffe
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1305514)
Das Problem mit der Laufzeit gilt aber auch für reine Unittests (z.B. Berechne alle Primzahlen von 1..n mit n ausreichend groß).
Deswegen lässt man solche Tests ja auch nicht ständig mitlaufen. Ich bin mir nur nicht sicher, ob die Definition eines Unittests von der Laufzeit abhängt. Oder gibt es irgendwo eine Definition, die Unittests generell als kurz (was auch immer das sein mag) festlegt?

AFAIK gibt es keine definierte, sondern höchstens eine implizierte Zeitbeschränkung. Ich lebe mit forcierten Zeitlimit auf Unit-Tests, um deren Charakter beizubehalten. Die Option, Ausnahmefälle zu bestimmen existiert, dafür gelten dann aber wieder Auflagen.
Beim Beispiel der Primzahlen macht es u.U. Sinn, einen Test zu haben, der länger braucht - allerdings darf der dann nur laufen, wenn auch der Code zur Primzahlenberechnung geändert wird.


Zitat:

Zitat von Uwe Raabe (Beitrag 1305514)
Es ist natürlich schon sinnvoll, kurze Tests spätestens beim Commit oder sogar "ständig" laufen zu lassen (Stichwort TestInsight) und längere Tests dem CI-System zu überlassen. Wie man diese Tests dann im einzelnen nennt, spielt eigentlich eine untergeordnete Rolle.

Bei mir laufen ALLE Unittests die durch den Code beeinflusst werden beim Commit; Wenn Schnittstellen zu anderen Systemen geändert werden, laufen die entsprechenden Tests auch mit. Das liegt aber an der Größe der Codebase der Aktivität darauf.

Zitat:

Zitat von Uwe Raabe (Beitrag 1305514)
Was mich bei einem solchen DB-Test eher stören würde, ist die schlechte Portierbarkeit wenn er Zugriff auf einen DB-Server mit einer definierten Datenbank haben muss. Was ist wenn der DB-Server nicht erreichbar ist? Wenn keine (passenden) DB-Treiber installiert sind? Wenn gleichzeitig ein anderer Prozess diese Datenbank manipuliert?

Deswegen sollte man eine Schnittstelle haben, die man durch einen Mock ersetzen kann. Wird die Schnittstelle (die auch der einzige Ort sein sollte, in dem DB-spezifische Queries generiert werden) geändert, müssen diese Tests mit DB-Anbindung laufen. Für alles andere nimmt man Mocks, die das Verhalten der Schnittstelle simulieren.

Zitat:

Zitat von Uwe Raabe (Beitrag 1305514)
Man muss auch sehen, was eigentlich getestet werden soll. Geht es vielleicht nur darum, ob die richtige SQL-Anweisung erzeugt wird? Das ließe sich natürlich auch ohne DB validieren.

Ja, wobei man auch wieder verifizieren muss: Was ist die richtige SQL-Anweisung?

Stevie 18. Jun 2015 22:38

AW: Unittests für DB-Zugriffe
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1305505)
Mögen die Dogmatiker hier jetzt auch hyperventilieren - das geht mir vollkommen am
Delphi-Quellcode:
end.
vorbei :wink:

Das hat nix mit Dogma zu tun, sondern mit genauen Begrifflichkeiten, da einige ständig Unit und Integrationstests (beide gleichermaßen wichtig!) in einen Topf werfen.

hoika 19. Jun 2015 05:00

AW: Unittests für DB-Zugriffe
 
Hallo,
nettes Thema habe ich da aufgeworfen:)

Zum Punkt Mock-Objekte:
Wie prüfe ich meine App beim Umstieg auf eine neue FB-Version?

Natürlich ohne die Mocks!

Mir ging es gerade und: Kommt hinten das richtige raus?

Heiko

Dejan Vu 19. Jun 2015 07:12

AW: Unittests für DB-Zugriffe
 
Wir haben (so wie jeder, denke ich) das gleiche Problem. Die Frage, die Du dir stellen musst, ist nicht: "Wie teste ich den Code, den ich geschrieben habe?" Sondern eher: "Wie schreibe ich Code, damit ich ihn testen kann?" Bei der DB-Frage würde ich wirklich alle Einzelkomponenten testen (deinen Provider brauchst Du nicht zu testen). Schreibe Dir doch DB-Unittests, die z.B. sicherstellen, das die Tabellen und Views ein bestimmtes Format haben. Auf der anderen Seite schreibst du die UT, die gegen genau dieses Layout prüfen.

Um einen (Blackbox)Integrationstest, der einfach prüft, was hinten rauskommt, kommst Du eh nicht herum. Vielleicht testest Du ja in der DB gegen die Tabelle (A,B,C) und im UT gegen (A,B,X). Beide Tests gelingen.

BUG 19. Jun 2015 11:50

AW: Unittests für DB-Zugriffe
 
Zitat:

Zitat von hoika (Beitrag 1305631)
Natürlich ohne die Mocks!

Imho lassen sich die Antworten so zusammenfassen: Das sind Integrationstest. Es empfiehlt sich, sie logisch von den Unit-Test zu trennen, aber es spricht nichts dagegen die gleiche Tool-Unterstützung wie für Unit-Tests zu verwenden.

Zitat:

Zitat von Dejan Vu (Beitrag 1305638)
Die Frage, die Du dir stellen musst, ist nicht: "Wie teste ich den Code, den ich geschrieben habe?" Sondern eher: "Wie schreibe ich Code, damit ich ihn testen kann?"

Die schwierigeren Varianten davon sind: "Wie teste ich den Code, den ich nicht geschrieben habe?" und "Wie schreibe ich Code um, damit ich ihn testen kann?" :stupid:

hoika 22. Jun 2015 04:45

AW: Unittests für DB-Zugriffe
 
Hallo,
genau diese Trennung der länger dauernden Tests bin ich am Überlegen.
Ich liege also zumindestens nicht so falsch mit meinem aktuellen Vorgehen.

Danke

Heiko

Dejan Vu 22. Jun 2015 05:07

AW: Unittests für DB-Zugriffe
 
Zitat:

Zitat von BUG (Beitrag 1305680)
Die schwierigeren Varianten davon sind: "Wie teste ich den Code, den ich nicht geschrieben habe?" und "Wie schreibe ich Code um, damit ich ihn testen kann?" :stupid:

1. Integrationtest.
2. SRP, OCP, DI, DRY.


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:17 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz