Testen mal anders: phpt

phpt ist ein schmuckes, kleines Testframework, welches u.a. auch zur PHP Quality Assurance verwendet wird, um damit PHP-eigene Funktionen in PHP zu testen. Wir beginnen mit einem Beispiel:

--TEST-- My first cool test! --FILE-- <?php  class Foobar { 	public function __construct() 	{ 		for ($i = 0; $i < 6; $i++) 		{ 			if ($i % 2 != 0) 				echo $i; 		} 	} }  new Foobar(); ?> --EXPECT-- 135 

Und das Beste: Mit PEAR kommt der Spaß gleich mit:

Pear run-tests

Pear run-tests

Das ists aber lang noch nicht gewesen. Man führe sich folgenden Test zu Gemüte:

--TEST-- Second example: errortesting --FILE-- <?php  $foo = array(1, 3) * array(2, 6); ?> --EXPECTF-- Fatal error: Unsupported operand types in %s.php on line %d 

Wir testen hier etwas, was schiefgehen soll. Dabei kommt gleich noch EXPECTF (für formatierte Ausgaben im Stil von scanf) zum Einsatz.

Aber es wird noch cooler. Es gibt sehr sinnvolle –BLÖCKE–, mit denen dann auch sowas realisiert werdern kann:

--TEST-- Test filter_input() with GET and POST data. --DESCRIPTION-- This test covers both valid and invalid usages of filter_input() with INPUT_GET and INPUT_POST data and several differnt filter sanitizers. --CREDIT-- Felipe Pena <felipe@php.net> --INI-- precision=14 --SKIPIF-- <?php if (!extension_loaded("filter")) die("Skipped: filter extension required."); ?> --GET-- a=<b>test</b>&b=http://example.com --POST-- c=http://example.com --FILE-- <?php var_dump(filter_input(INPUT_GET, "a", FILTER_SANITIZE_STRIPPED)); var_dump(filter_input(INPUT_GET, "b", FILTER_SANITIZE_URL)); var_dump(filter_input(INPUT_POST, "c", FILTER_SANITIZE_URL)); ?> --EXPECTF-- string(4) "test" string(18) "http://example.com" string(18) "http://example.com" 

Hier schön zu sehen: Per –INI– werden Werte der php.ini für diesen Test überschrieben. Per –SKIPIF– können wir den Test überspringen, wenn die notwendigen Voraussetzungen nicht erfüllt sind. Ein Test der PHP-Filter-Funktionen wäre ohne eine geladene Filter-Extension schließlich witzlos. Anderes schönes Beispiel dazu:

--SKIPIF-- <?php  if (PHP_INT_SIZE != 8) die("skip this test is for 64bit platforms only"); ?> 

Mit –GET– und –POST– lassen sich schließlich auch Requests simulieren. In Anlehnung an die tearDown()-Methode von PHPUnit gibt es zum Aufräumen noch:

--CLEAN-- <?php       unlink($temp_filename); ?> 

Weiterhin lassen sich auch Request-Header setzen und sogar ein Autoloader für vollwertige Unit-Tests einbetten:

--TEST-- Test filter_input() with GET and POST data. --FILE-- <?php function __autoload($classname) { 	require $classname.".php"; } var_dump(SomeClass::add(2, 3)); ?> --EXPECT-- int(5) 

Wer nach diesem kurzen Anriss richtig einsteigen will, findet hier die Basics, eine Übersicht über alle Möglichkeiten und auf den QA-Seiten den ein oder anderen interessanten Einblick in das PHP-interne Testgebahren.

Erwähnenswert ist zum Abschluss noch das tolle Fehlerverhalten. Wir legen bewusst einen falschen Test an, um das mal zu demonstrieren:

--TEST-- Test that is intentionally incorrect --FILE-- <?php var_dump(cos(90 * 2*M_PI)); ?> --EXPECT-- int(0) # erwischt? cos(90) = 1 ;) 

Der Test schlägt also fehl. Freundlicherweise wird zu unserer Testdatei ins Verzeichnis noch eine [testname].log angelegt, die wie folgt aussieht:

---- EXPECTED OUTPUT int(0) # erwischt? cos(90) = 1 ;) ---- ACTUAL OUTPUT int(1) ---- FAILED 

Da lässt sich also echt was mit anfangen. Korrigiert man den Test, werden die nun überflüssigen Fehler-Logdateien selbstständig wieder bereinigt, sodass kein Dateimüll entsteht. phptest ist meiner Meinung nach völlig zu Unrecht so unbekannt.