Seit langem bin ich mal wieder aktiv in der Implementierung einer Komponente, wenn auch erst mal nur ein Prototyp.
Die Persistenz ist – nach dem neusten Trend “back to the roots” – nur noch mit dem JdbcTemplate von Spring gemacht. Da kann man wieder richtiges SQL schreiben und weiß auch genau was passiert (bei Hibernate war ich mir nicht immer so ganz sicher).
Als es dann ans Testen ging und ich mir Gedanken um die Testabdeckung machte, fiel mir auf, dass das was bei if-Anweisungen oder bedingter Zuweisung im Java-Code als “missed 2 of 4 branches” an gemeckert wurde, an vielen Stellen in den Where-Clauses der SQL-Statements genauso auftritt.
Die Coverage in Java war also bei mancher Methode auf 100% aber das SQL-Statement ließ viele Varianten von ResultSets zu je nach dem, was man für Testdaten verwendet und welche konkreten Parameter man bindet.
Wie also läßt sich die SQL-Coverage messen?
SQL tracen
Zunächst einmal ist es nützlich die SQL-Statement mitschrieben zu lassen, die tatsächlich ausgeführt werden inklusive der aktuell gebundenen Parameter. Hierfür kann man Tools wie http://code.google.com/p/log4jdbc-remix/ bzw. http://code.google.com/p/log4jdbc/ verwenden. Diese JDBC-Treiber arbeiten als Proxy und werden einfach “zwischen” die Applikation und den echten Treiber “gehängt”. Dadurch wird es einfach möglich alle SQL-Statements die man bei Ablauf einer Testsuite an die Datenbank schickt mitzuschreiben.
Aber leider weiss man damit immer noch nicht, ob man nun alle möglichen “Zweige” aller Where-Bedingungen aller SQL-Statements durchlaufen hat.
SQL Rules und QAShrink
SQL Rules und QAShrink sind zwei Tool, die genau darüber Aufschluss geben können. Sie sind in der Lage ein gegebenes SQL-Statement zu analysieren nach der “Full Predicate Coverage” Methode. Es werden also Regeln erzeugt, die alle Verzweigungen oder Varainten die ein SQL-Statement erzeugen kann, berücksichtigt.
Dabei werden nicht nur Where-Bedingungen in Betracht gezogen, sondern natürlich auch Joins oder Group By-Klauseln. SQLRules zeigt zu einen einzelnen Statement diese Rules an, so dass man sich anschauen kann, welche möglichen “Pfade” zur Ergebnisfindung durchlaufen werden können.
Regeln anwenden
Im nächsten Schritt lassen sich diese Regeln dann gegen einen Testdatenbestand anwenden / testen. Als Ergebnis bekommt man eine Aussage, ob die betreffende Regel verwendet wurde oder nicht, also ob dieser Pfad bei den zugrunde gelegten Daten durchlaufen wurde oder nicht. Das ist genau die SQL-Coverage die man braucht.
Das andere Tool QAShrink kann dieses Prinzip gleich auf eine ganze Liste von SQL-Statements anwenden. Es erzeugt dann Aussagen bzgl. der Coverage der SQL-Statements und der Vollständigkeit bzw. der Redundanz der Testdaten.
Auf diese Weise kann man also ziemlich schnell herausfinden, welche Testdaten überflüssig und welche noch zu ergänzen sind, um – bei gegebener Liste der SQL-Statements – die SQL-Coverage möglichst hoch zu machen.
Zusammenfassung
Das Vorgehen zum Erreichen einer möglichst hohen SQL-Coverage läßt sich also so zusammenfassen:
- Mit einem JDBC-Proxy Treiber erzeugt man eine Liste von konkreten SQL-Abfragen, die von einer TestSuite mit hoher Code-Coverage erzeugt wird.
- Die Liste der SQL-Statemant füttert man in QAShrink und läßt sie gegen den gleichen Testdatenbestand wie die TestSuite laufen.
- Anhand der Ergebnisse kann man den Testdatenbestand so lange um Datensätze ergänzen, bis eine optimale SQL-Coverage erreicht ist.
Links zu den Tools:
http://in2test.lsi.uniovi.es/sqltools/sqlrules/
http://in2test.lsi.uniovi.es/sqltools/qashrink/