Friday, March 12, 2010

Devel::Cover für CGI-Programme

Devel::Cover ist ein super Tool, mit dem man prüfen kann, ob die Testsuite für ein Programm/Modul wirklich den gesamten Code testet. 100% Abdeckung zu erreichen ist äußerst schwierig. Und selbst bei 98% Testabdeckung heißt es nicht, dass in der Software keine Fehler mehr sind - wie Curtis 'Ovid' Poe diese Woche feststellen musste.

Devel::Cover misst die Abdeckung für verschiedene Sachen:
  • Statements
  • Branches
  • Conditions
  • POD
  • Subroutines
100% Abdeckung bei Statements sagt nicht besonders viel aus. Nimmt man als Beispiel "print 'yes' if $x || $y", dann kann man 100% erreichen, indem man $x einen "wahren" Wert gibt. Aber man hier nicht alle Fälle getestet.

Am meisten nutze ich die Abdeckung der "Conditions". Da hier von Devel::Cover alle Kombinationen von Bedingungen angezeigt werden und ob man das getestet hat. Hier kann man noch große Lücken in den Tests aufdecken:


Zu genau will ich hier aber gar nicht auf Devel::Cover eingehen.

Man braucht nicht immer eine Testsuite, um mit dem Tool etwas sinnvolles zu tun. Gestern wurde ich gefragt, ob und wie man einfache CGI-Programme damit überprüfen kann. Hintergrund ist der, dass unnötiger Code identifiziert werden sollte, damit das aufgeblähte Skript etwas zusammengeschrumpft werden kann.

Das CGI-Skript braucht keine Parameter, so dass ein einziger Durchlauf reicht, um unnötigen Code zu identifizieren. Bei etwas komplexeren Skripten muss man mehrere Läufe mit unterschiedlichen Bedingungen starten.

Mit zwei zusätzlichen Zeilen in der Apache-Config kann man Devel::Cover für alle CGI-Skripte aktivieren:

SetEnv DEVEL_COVER_OPTIONS "-ignore,CGI,-silent,1"
SetEnv PERL5OPT "-MDevel::Cover"


Und für ein einziges Skript fügt man diese Zeile in das Skript ein:

use Devel::Cover qw(-ignore CGI -silent 1);


Mit PERL5OPT kann man dem Perl-Interpreterer Optionen mitgeben. In diesem Fall ist das "-MDevel::Cover", was bewirkt, dass Devel::Cover eingebunden wird. Die Optionen für Devel::Cover sagen folgendes aus:

-ignore,CGI => Erstelle für Dateien, die CGI im Namen/Pfad haben keine Auswertung
-silent,1 => Mache keine Ausgaben
Vor allem letztere Option ist wichtig, da sonst ein "Premature end of header" kommt. Devel::Ignore gibt nämlich eine Auswertung auf STDOUT aus, bevor das Skript einen Header senden konnte. Ist das ausgeschaltet, erstellt Devel::Cover einfach nur die Datenbank, die dann in HTML umgewandelt werden kann.

No comments: