test.ical.ly | getting the web by the balls

Feb/10

3

Testabdeckung (Code Coverage) mit PHPUnit in einer symfony Applikation

Nachdem ich nun mit PHPUnit unterwegs bin und bereits die ersten Testergebnisse in Hudson eingebunden habe, will ich nun wissen, wie gut meine Testabdeckung ist. Ich hatte dazu ja bereits vor einiger Zeit einen kleinen Post über die NPath Komplexität geschrieben.

Aber zunächst will ich PHPUnit (und Xdebug) erstmal dazu bringen, mit meine Testabdeckung zu zeigen.

Das mache ich per mit folgendem Aufruf:

$ phpunit –coverage-html web/report/ plugins/wgtSitePlugin/test/AllTests.php

Das Ergebnis ist ein vollständiger HTML Report.

PHPUnit Code Coverage Report

Standard PHPUunit Code Coverage Report

Als nächstes will ich die Frage stellen, was überhaupt alles abgedeckt werden muss und dann wie ich die nicht abzudeckenden Teile “wegkonfiguriere”.

Wie man an dem obigen Diagramm sieht, steht es nicht gut um meine Testabdeckung. Aber schauen wir uns doch mal an, was wir z.B. unter lib alles vergessen haben.

Detailansicht des PHPUnit Code Coverage Reports

Man kann also erkennen, dass die berechnete Code Coverage auch den symfony Code mit berücksichtigt.

Ohne über dessen Testabdeckung urteilen zu wollen, kann ich doch feststellen, dass ich mich hier überhaupt garnicht verantwortlich fühle. Im Gegenteil. Es fühlt sich einfach falsch an, wenn meine Testabdeckung, die im Plugin immerhin 40,51% aller Code Zeilen ausmacht, durch eine eingestezte fremde Software Komponente auf nur noch 14,20% reduziert wird.

Eine andere Stelle, die bisher nicht abgedeckt war ist folgende:

Eine von symfony erstellte Klasse in der Code Coverage Detailansicht

Eine von symfony erstellte Klasse in der Code Coverage Detailansicht

Mein erster Impuls ist, nach einem Weg zu suchen, wie ich symfony und die von symfony generierten Klassen aus der Berechnung ausschliessen kann. Aber vielleicht ist das etwas verfrüht und ich sollte mir erstmal Gedanken machen, nach welchen Kriterien ich etwas ausschliessen kann.

Was muss ich für die Erhebung meiner Testabdeckung berücksichtigen und was kann ich ausschliessen?

Es gibt Code in meinem Projekt, der sich nicht unter meiner Kontrolle befindet, nämlich die symfony Klassen. Natürlich kann ich auch zu deren Testabdeckung beitragen, indem ich Tests schreibe und diese an die symfony Core Developer weitergebe, jedoch geschehe sowas in einem völlig anderen Kontext und ausserhalb meines Projektes.

  • Eingesetzte Software Komponenten, die nicht unter der eigenen (Versions-) Kontrolle stehen, müssen nicht von eigenen Tests abgedeckt sein

Damit hätte ich also begründet, dass ich symfony ausschliessen darf, aber auch z.B. Zend Framework Komponenten, PEAR Bibliotheken oder andere Third Party Software.

Aber kann ich mit diesem Kriterium auch von symfony generierten Code ausschliessen?

Wenn man sich anschaut, wozu dieser generierte Code da ist und was er beinhaltet stellt man fest, dass symfony immer dort Klassen generiert, wo mir die Möglichkeit gegeben werden muss, eigenes Verhalten zu implementieren. Im Fall der obigen frontendConfiguration Klasse habe ich einen Ort, an dem ich Applikations spezifische Konfigurationen vornehmen kann. Der Klassenrumpf ist zunächst leer.

Schliesse ich nun diese Art von Code aus und füge aber später doch eigenen Code dort ein, wird dieser für die Code Coverage nicht betrachtet und mir wird u.U. nicht auffallen, dass ich vergessen habe ihn zu testen. Ich stelle also fest: obwohl ich nicht für die Erstellung der jeweiligen Datei verantwortlich war, steht sie doch unter meiner Kontrolle und muss somit auch eine Testabdeckung erfahren. Solange der Klassenrumpf aber leer ist, kann ich sie entweder ignorieren oder aber einen dazugehörigen TestCase erstellen, der bis auf eine Instanzierung nichts weiter vornimmt.

Und wie schliesse ich jetzt diese Teile meines Projektes aus?

PHPUnit bietet eine Menge Optionen über die Kommandozeile, um aber Bereiche auszuschliessen wäre dieses viel zu unkonfortabel, weswegen man seine Konfiguration in einem XML ablegen kann. Diese Konfigurationsdatei kann ich entweder über die –configuration <file> Option angeben, oder aber ich nenne sie einfach phpunit.xml und lege sie dort ab, wo ich auch den PHPUnit Aufruf starte, in meinem Fall im symfony Root Dir.

Hier eine einfache Beispiel Konfiguration noch ohne Ausschlüsse.




Um nun sowohl symfony als auch das von mir verwendete sfTaskExtraPlugin auszuschliessen, muss ein Blacklist Filter hinzugefügt werden. Das Ganze sieht dann so aus:



  
    
      ./lib/vendor/
      ./plugins/sfTaskExtraPlugin/
    
  

Wenn ich nun PHPUnit erneut laufen lasse, sieht der generierte Report anschliessend wie folgt aus:

PHPUnit Code Coverage Report nach dem Ausschluss von Third Party Komponenten

PHPUnit Code Coverage Report nach dem Ausschluss von Third Party Komponenten

Das sieht doch deutlich besser aus! :)

Morgen werde ich mich dann mal weiter mit den Ausnahmen beschäftigen und mit der Frage, ob eine 100%ige Testabdeckung erreichbar oder überhaupt erstrebenswert ist.

· · · · ·



<<

>>

Theme Design by devolux.nh2.me