<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>// der php hacker &#187; Testing</title>
	<atom:link href="http://phphacker.net/category/testing/feed/" rel="self" type="application/rss+xml" />
	<link>http://phphacker.net</link>
	<description>ein php blog</description>
	<lastBuildDate>Wed, 27 Jan 2010 12:06:22 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.6</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Warum Unit-Tests keine Qualitätssicherung sind</title>
		<link>http://phphacker.net/2009/02/19/warum-unit-tests-keine-qualitatssicherung-sind/</link>
		<comments>http://phphacker.net/2009/02/19/warum-unit-tests-keine-qualitatssicherung-sind/#comments</comments>
		<pubDate>Thu, 19 Feb 2009 08:33:27 +0000</pubDate>
		<dc:creator>Cem Derin</dc:creator>
				<category><![CDATA[Entwicklung]]></category>
		<category><![CDATA[Hintergrund]]></category>
		<category><![CDATA[Testing]]></category>

		<guid isPermaLink="false">http://phphacker.net/?p=484</guid>
		<description><![CDATA[Janusz fasst sehr schön zusammen, warum Unit-Tests nicht mit einer Qualitätssicherung gleichzustellen sind. Besonders der Abschnitt, was Unit tests aussagen bzw. was eben nicht finde ich sehr gelungen. Zusammengefasst: Unit testing ist wichtig, hört nicht auf damit! Unit tests prüfen aber nicht die Funktionalität eurer Software, sondern eurer Komponenten (richtig, evtl. kommt auch daher der [...]]]></description>
			<content:encoded><![CDATA[<p>Janusz fasst sehr schön zusammen, <a href="http://agilesoftwaredevelopment.com/blog/janusz-gorycki/your-unit-tests-are-useless">warum Unit-Tests nicht mit einer Qualitätssicherung gleichzustellen sind</a>. Besonders der Abschnitt, was Unit tests aussagen bzw. was eben nicht finde ich sehr gelungen. Zusammengefasst: Unit testing ist wichtig, hört nicht auf damit! Unit tests prüfen aber nicht die Funktionalität eurer Software, sondern eurer Komponenten (richtig, evtl. kommt auch daher der Name <em>Unit </em>test <img src='http://phphacker.net/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' />  ). Wir testen also, ob Methoden wie erwartet reagieren, ob sie Überhaupt vorhanden sind &#8211; ob die Komponente <em>as designed</em> funktioniert.</p>
<p>Ob die Applikation an sich funktioniert kann man damit natürlich nicht herausfinden. Zum einen, weil ein Unit-Test ohne Sinn und Verstand geschrieben werden kann &#8211; Man sollte sich also nicht zu viel auf die hübsche Grüne Ausgabe einbilden &#8211; Zum anderen, weil ein Applikation (also die Summe mehrerer Komponenten (die evtl. alle fehlefrei funktionieren)) wiederum falsch zusammengesetzt worden sein kann. <span id="more-484"></span></p>
<p>Und dann gibt es da ja noch etwas, dass einem das Entwicklerleben immer wieder schwer macht:  Sonderfälle. Das sind die Dinge, die man nie mit einplant, die aber ständig auftreten und alles geplante gekonnt umschiffen. Diese kann man im Vorfeld einfach nicht mit Unit tests abfackeln (aber man kann prüfen, was passiert, wenn einer Eintritt &#8230;).</p>
<p>Daher: Unit tests sind und bleiben Unit tests (obwohl ich hierzu auch schon Interaktionstests zuzählen würde). Ein Systemtest kann nur schwer automatisiert durchgeführt werden. In Bezug auf Webapplikationen kommt man da mit Webtests schon recht weit, aber ums manuelle &#8220;durchklicken&#8221; wird man nie herum kommen. Sorry <img src='http://phphacker.net/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://phphacker.net/2009/02/19/warum-unit-tests-keine-qualitatssicherung-sind/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Selenium Guide, Teil 2: Selenium Remote Control nutzen</title>
		<link>http://phphacker.net/2009/02/12/selenium-guide-teil-2-selenium-remote-control-nutzen/</link>
		<comments>http://phphacker.net/2009/02/12/selenium-guide-teil-2-selenium-remote-control-nutzen/#comments</comments>
		<pubDate>Thu, 12 Feb 2009 07:30:51 +0000</pubDate>
		<dc:creator>Cem Derin</dc:creator>
				<category><![CDATA[Testing]]></category>

		<guid isPermaLink="false">http://phphacker.net/?p=424</guid>
		<description><![CDATA[
Im letzten Teil habe ich erklärt, was Selenium ist, dass Webtests keine zu vernachlässigender Bestandteil eines profesionellen Deployments von Webapplikationen sind und wie man mithilfe der Selenium-IDE Tests erstellen kann.
Heute möchte ich euch zeigen, dass man verdammt schnell und sehr einfach einen Selenium Remote Control Server aufsetzen kann, und dieser mit einer ganzen Reihe von [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignnone size-full wp-image-367" src="http://phphacker.net/wp-content/uploads/2009/02/selenium_shot.jpg" alt="selenium_shot" width="1000" height="175" /></p>
<p>Im letzten Teil habe ich erklärt, was <strong>Selenium </strong>ist, dass Webtests keine zu vernachlässigender Bestandteil eines profesionellen <strong>Deployments </strong>von Webapplikationen sind und wie man mithilfe der <strong>Selenium-IDE</strong> Tests erstellen kann.</p>
<p>Heute möchte ich euch zeigen, dass man verdammt schnell und sehr einfach einen <strong>Selenium Remote Control Server</strong> aufsetzen kann, und dieser mit einer ganzen Reihe von Sprachen direkt ansprechbar ist. In unserem Beispiel werden wir uns natürlich auf PHP konzentrieren.</p>
<p>Hier noch einmal die Artikelübersicht:</p>
<ol>
<li><a href="http://phphacker.net/2009/02/04/selenium-guide-teil-1-sinnvolle-tests-erstellen/">Sinnvolle Tests erstellen</a></li>
<li><strong>Selenium Remote Control nutzen</strong></li>
<li>Tests automatisieren und in Unittest-Frameworks einbinden</li>
</ol>
<p><span id="more-424"></span></p>
<h2>Testumgebung</h2>
<p>Bevor man einen RC-Server aufsetzen kann, muss man sich entscheiden, welche Browser man überhaupt testen will. Verzichtet man auf Nieschenbrowser wie <strong>Konqueror </strong>und <strong>Camino</strong>, so wird ein Windows Server ausreichen.</p>
<p>Nachdem alo der Windows Server breit steht, kann man sich von der <a href="http://seleniumhq.org/">Selenium-Seite</a> direkt das RC-Paket holen, entpacken und den Server starten. Der Server wird im Verzeichnis <em>selenium-server-xx</em> liegen. Starten kann man ihn einfach mit dem Befehl <em>java -jar selenium-server.jar</em>. Standardmäßig startet Selenium RC auf Port <em>4444</em>. Wünscht man einen anderen Port, so kann man diesen mit dem Schalter <em>-port &lt;wunschport&gt;</em> beim Starten einstellen. Das war es dann auch eigentlich schon. Nun müssen wir den <strong>Server </strong>nur noch ansprechen.</p>
<h2>Einen Test an den RC-Server senden</h2>
<p>Da ich in hier vornehmlich PHP-Themen behandle, wollen wir Tests natürlich auch mit PHP an den RC-Server senden. Selenium bietet einen Treiber für <strong>PHPUnit </strong>an. Dieses UnitTest-Framework wird mit <strong>PEAR </strong>ausgeliefert. Evtl. muss es nachinstalliert werden &#8211; wie das funktioniert erfahrt ihr auf der <a href="http://www.phpunit.de/">PHPUnit-Seite</a>. Dann sollte eigentlich alles automatisch passieren.</p>
<p>Bis hier die <strong>Theorie</strong>. Während ich das alles ausprobiert habe, ist nicht die Bohne automatisch passiert. Ich musste alles nachbearbeiten, anpassen, <strong>Pfade</strong>- und <strong>Klassennamen</strong> korrigieren. Wenigstens der Server hat keine Faxen gemacht. Einzig <strong>Safari </strong>wollte nicht testen, aber der wird offiziell unter Windows ja auch nur mit „<strong>may work</strong>&#8221; aufgeführt.</p>
<p>Dazu muss ich gestehen, dass ich kein großer Freund von PHPUnit bin. Das liegt in erster Linie daran, dass es so fest in PEAR eingebacken ist &#8211; was ich auch nicht mag. Wie dem auch sei. Ich will Selenium für <strong>SimpleTest </strong>benutzen. Dazu schnappt ihr euch einfach die im RC-Archiv vorhandenen Selenium-PHP-Dateien und passt sie ein bischen an. Zunächst erweitert die <em>Exception </em>nicht mehr die PEAR-Exception. Darüberhinaus erweitert die <em>Klasse Testing_Selenium</em> die Klasse <em>UnitTestCase</em> erweitert. Dann baut ihr noch eine neue Methode ein:</p>
<pre>    public function run(SimpleReporter $reporter) {
    	$this-&gt;start();
    	$return = parent::run($reporter);
    	$this-&gt;stop();
    	return $return;
    }</pre>
<p>Und fertig. Die TestCases die ihr mit der Selenium-IDE erstellt könnt ihr nun aus der IDE als PHP herauskopieren und in eure Tests einfügen. Der <strong>Konstruktor </strong>rist eigentlich selbsterklärend. Wie man nun <strong>UnitTests </strong>schreibt, werde ich hier aber nicht mehr erklären <img src='http://phphacker.net/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<h1>Und nun?</h1>
<p>Im letzten Teil werde ich erklären, wie man die in PHP überführten Tests in seinen <strong>Deploymentprozess </strong>integrieren kann, wie man schnell ordentliche Tests schreibt und mittels <strong>Selenium Grid</strong> dafür sorgt, dass man automatisiert und ohne <strong>Performanceverlust </strong>und <strong>Bottleneck </strong>testen kann.</p>
<p>Ich hoffe ich konnte euch Selenium näher bringen. Sollten noch Fragen offen sein, so scheut nicht, die <strong>Kommentarfunktion </strong>zu bemühen <img src='http://phphacker.net/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://phphacker.net/2009/02/12/selenium-guide-teil-2-selenium-remote-control-nutzen/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Selenium Guide, Teil 1: Sinnvolle Tests erstellen</title>
		<link>http://phphacker.net/2009/02/04/selenium-guide-teil-1-sinnvolle-tests-erstellen/</link>
		<comments>http://phphacker.net/2009/02/04/selenium-guide-teil-1-sinnvolle-tests-erstellen/#comments</comments>
		<pubDate>Wed, 04 Feb 2009 07:30:52 +0000</pubDate>
		<dc:creator>Cem Derin</dc:creator>
				<category><![CDATA[Testing]]></category>

		<guid isPermaLink="false">http://phphacker.net/?p=366</guid>
		<description><![CDATA[
Pekka kommt nicht mit Selenium klar, und auch sonst scheinen Frontend- bzw Webtests kein Thema zu sein. Entweder fahren viele Entwickler die Schiene &#8220;Geht eh nicht vernünftig&#8221; oder blenden die Problematik komplett aus. Da aber testgetriebene Entwicklung ist kein Buzzword sondern ein wichtiges Dogma ist, dass auch in Deutschland durchaus Einzug in den professionellen Entwickleralltag [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignnone size-full wp-image-367" title="selenium_shot" src="http://phphacker.net/wp-content/uploads/2009/02/selenium_shot.jpg" alt="selenium_shot" width="1000" height="175" /></p>
<p><a href="http://www.pekkagaiser.de/">Pekka</a> kommt nicht mit <a href="http://seleniumhq.org/"><strong>Selenium</strong></a><strong> </strong>klar, und auch sonst scheinen <strong>Frontend</strong>- bzw <strong>Webtests </strong>kein Thema zu sein. Entweder fahren viele Entwickler die Schiene &#8220;<em>Geht eh nicht vernünftig</em>&#8221; oder blenden die Problematik komplett aus. Da aber <strong>testgetriebene Entwicklung</strong> ist kein Buzzword sondern ein wichtiges Dogma ist, dass auch in Deutschland durchaus Einzug in den professionellen Entwickleralltag gefunden hat,  ist es nur konsequent die Benutzeroberfläche einzubeziehen. Wie man das mit Selenium machen kann, möchte ich in einer kleinen Artikelreihe erlätern. Sie wird aus folgenden Artikeln bestehen:</p>
<ol>
<li><strong>Sinnvolle Tests erstellen</strong></li>
<li>Selenium Remote Control nutzen</li>
<li>Tests automatisieren und in Unittest-Frameworks einbinden</li>
</ol>
<h2><span id="more-366"></span>Vorbereitungen</h2>
<p>Unter Zuhilfenahme der <strong>Selenium-IDE</strong> (ein Firefox-Plugin) lassen sich Tests angenehm schnell &#8220;aufnehmen &amp; abspielen&#8221;, speichern, archivieren, weiterreichen. Diese also schnell <a href="https://addons.mozilla.org/de/firefox/addon/2079">installieren</a>, einen Ordner &#8220;tests&#8221; irgendwo auf unserem Rechner anlegen und dann kann es auch schon losgehen.</p>
<h2>Was testen?</h2>
<p>Was genau man testet hängt in erster Linie von der <strong>Applikation </strong>ab. In der Regel sollte man Workflows innerhalb seiner Applikation testen. Dabei sollte darauf geachtet werden, bewusst ungültige Daten einzugeben und auf das Erscheinen der Fehlermeldungen zu prüfen. Selenium bietet die möglichkeit, den <strong>Seitentitel </strong>bei jedem Aufruf einer Seite direkt in den Test aufzunehmen und zu prüfen. Diese Option kann man aktivieren, wenn der Seitentitel stark an den <strong>Content </strong>gekoppelt ist.</p>
<h2>Tests strukturieren</h2>
<p>Es ist unerlässlich, seine Tests sauber zu strukturieren. Am besten teilt man diese in kleine <strong>thematisch zusammenhängende Häppchen</strong> auf. Vor allem aber sollten die einzelnen Tests selbstständig auf die Seite navigieren, von der sie starten. Darüber hinaus müssen die Tests in sich geschlossen sein, um eine <strong>Kettenreaktion von Fehlschlägen</strong> zu vermeiden.</p>
<h2>Tipps &amp; Kniffe</h2>
<p>Es empfiehlt sich, seine Tests immer direkt einmal durchlaufen zu lassen. Dabei wird euch schnell auffallen, dass Selenium sich manchmal etwas zickig anstellt. Da wird sporadisch ein <strong>Link nicht gefunden</strong>, der eindeutig da ist, Eingaben können nicht gemacht werden und <strong>Textprüfungen schlagen fehl</strong>. In den meisten Fällen muss man dann einfach nur die <strong>Geschindigkeit </strong>etwas herunterdrehen. Ich habe gute Erfahrungen mit einer <strong>2/3</strong> Geschwindigkeit gemacht. Je nach Komplexität der Abfragen solltet Ihr das noch weiter minimieren. Sollte das immer noch nichts bringen, solltet ihr einen Blick auf die Befehle vor dem Fehlschlag werfen. Häufig steht dort ein &#8220;<strong>click</strong>&#8221; Befehl. Ersetzt diesen gegen einen &#8220;<strong>clickAndWait</strong>&#8220;, und das Problem verschwindet in der Regel wieder.</p>
<h2>Und nun?</h2>
<p>Erstellt nun eine (oder mehrere) <strong>Testsuite</strong>(s) für eure Applikation. Lasst diese einfach mal nach ein paar Änderungen gegen eure <strong>Applikation </strong>testen. Ihr werdet feststellen, dass sich eure Applikation an den unmöglichsten stellen stark anders als zuvor verhält.</p>
<p>Im nächsten Teil werde ich dann erklären, wie man die <strong>Selenium Remote Control</strong> nutzen kann.</p>
]]></content:encoded>
			<wfw:commentRss>http://phphacker.net/2009/02/04/selenium-guide-teil-1-sinnvolle-tests-erstellen/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Firebug im Internet Explorer</title>
		<link>http://phphacker.net/2009/01/22/firebug-im-internet-explorer/</link>
		<comments>http://phphacker.net/2009/01/22/firebug-im-internet-explorer/#comments</comments>
		<pubDate>Thu, 22 Jan 2009 13:00:49 +0000</pubDate>
		<dc:creator>Cem Derin</dc:creator>
				<category><![CDATA[Entwicklung]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Testing]]></category>

		<guid isPermaLink="false">http://phphacker.net/?p=288</guid>
		<description><![CDATA[
Welcher Webworker kennt das nicht: Man baut Super-Features mittles JavaScript in seine Webanwendung, die das Leben des Benutzers erleichtern, die Anwendung mehr und mehr wie eine Desktopsoftware wirken lässt. Man benutzt Bibliotheken, damit eine größtmögliche Browserkompatibilität erreicht wird. Aber irgendwie zickt der Internet Explorer immer rum und hält sich darüberhinaus auch noch sehr bedeckt wenn [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://phphacker.net/wp-content/uploads/2009/01/ie_mac.png"><img class="alignnone size-full wp-image-290" title="ie_mac" src="http://phphacker.net/wp-content/uploads/2009/01/ie_mac.png" alt="ie_mac" width="536" height="154" /></a></p>
<p>Welcher Webworker kennt das nicht: Man baut Super-Features mittles <strong>JavaScript</strong> in seine Webanwendung, die das Leben des Benutzers erleichtern, die Anwendung mehr und mehr wie eine Desktopsoftware wirken lässt. Man benutzt Bibliotheken, damit eine größtmögliche Browserkompatibilität erreicht wird. Aber irgendwie zickt der <strong>Internet Explorer</strong> immer rum und hält sich darüberhinaus auch noch sehr bedeckt wenn es ans <strong>Debugging</strong> geht.</p>
<p><span id="more-288"></span></p>
<p><a href="http://phphacker.net/wp-content/uploads/2009/01/screen.png"><img class="alignleft size-thumbnail wp-image-297" title="screen" src="http://phphacker.net/wp-content/uploads/2009/01/screen-150x150.png" alt="screen" width="150" height="150" /></a>Mehr als einmal wünschte ich mir, dass ich im IE ordentlich debuggen könnte. Doch den <strong>Firebug</strong> wird es wohl auf ewig nur für den Firefox geben. Denkste! Es gibt eine <strong>Lite Version</strong> für den Internet Explorer, Opera und Safari. Das ganze lässt sich einfach über ein Bookmarklet einbinden (dazu einfach diesen <a href="javascript:var%20firebug=document.createElement('script');firebug.setAttribute('src','http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js');document.body.appendChild(firebug);(function(){if(window.firebug.version){firebug.init();}else{setTimeout(arguments.callee);}})();void(firebug);">Link</a> Bookmarken). Der Funktionsumfang ist natürlich eingeschränkt (wie man sich bei dem Zusatz &#8220;lite&#8221; schon denken konnte), aber es ist, jedenfalls was den IE betrifft, wesentlich mehr als man vom Hause Microsoft aus geliefert bekommt.</p>
<p>Wie man das Teil auch offline benutzen kann, wird auf der Seite des Lite Projektes erklärt: <a href="http://getfirebug.com/lite.html">GetFireBug.com</a></p>
]]></content:encoded>
			<wfw:commentRss>http://phphacker.net/2009/01/22/firebug-im-internet-explorer/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Webhooks mit PHP</title>
		<link>http://phphacker.net/2009/01/13/webhooks-mit-php/</link>
		<comments>http://phphacker.net/2009/01/13/webhooks-mit-php/#comments</comments>
		<pubDate>Tue, 13 Jan 2009 20:49:19 +0000</pubDate>
		<dc:creator>Cem Derin</dc:creator>
				<category><![CDATA[Entwicklung]]></category>
		<category><![CDATA[Testing]]></category>

		<guid isPermaLink="false">http://phphacker.net/?p=235</guid>
		<description><![CDATA[
Heute ein paar Gedanken zu Webhooks, deren Sinn und das man sie doch bitte so schnell wie möglich so häufig wie möglich anbieten solle.

Was sind Hooks?
In erster Linie ist ein Hook &#8211; wie man an meiner unglaublich kreativen Illustration erkennen kann &#8211; ein Haken. Allerdings nicht einer der Negativen, die man immer bei zu toll [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignnone size-full wp-image-245" title="Angelhaken" src="http://phphacker.net/wp-content/uploads/2009/01/hooks_d.jpg" alt="hooks_d" width="520" height="202" /></p>
<p>Heute ein paar Gedanken zu Webhooks, deren Sinn und das man sie doch bitte so schnell wie möglich so häufig wie möglich anbieten solle.</p>
<p><span id="more-235"></span></p>
<h2>Was sind Hooks?</h2>
<p>In erster Linie ist ein <a href="http://de.wikipedia.org/wiki/Hook_(EDV)">Hook</a> &#8211; wie man an meiner unglaublich kreativen Illustration erkennen kann &#8211; ein Haken. Allerdings nicht einer der Negativen, die man immer bei zu toll klingenden Sachen sucht, sondern ein durchaus Nützlicher und Brauchbarer. An diesen Haken hängen wir nämlich unseren Code.</p>
<p><!--more--></p>
<p>Hooks kennt man zum Beispiel schon von <a href="http://de.wikipedia.org/wiki/Subversion_(Software)">SVN</a>. Stellen wir uns folgende Situation vor: Nach jedem Commit in unser Repository soll das Team benachrichtigt werden, dass ein neuer Commit stattgefunden hat. Jetzt hätten die SVN-Entwickler eine solche Funktionalität direkt in die Software einbauen können. Würde auch Sinn ergeben, denn ein solcher Anwendungsfall ist durchaus üblich.</p>
<p>Stellen wir uns aber nun weiter vor, dass wir nach jedem Commit in den Hauptentwicklungszweig eine Version auf einem Testserver deployen wollen. Auch ein solcher Anwendungsfall ist ziemlich häufig anzutreffen. Spätestens wenn es darum geht, wie eine solche Deployroutine aussehen könnte, wäre den SVN-Entwickler aber aufgefallen, dass sie ja gar nicht wissen, um was für eine Programmiersprache es sich handelt. Schließlich könnte die Software statt in PHP genau so gut in Java, in ASP, in Perl oder in sonst einer Programmiersprache geschrieben worden sein. Oder ganz anders: Es handelt sich gar nicht um ein Webprojekt, sondern um eine Desktopsoftware.</p>
<p>Da haben sich die Entwickler von SVN einem Prinzip bedient, das alles andere als neu ist: Sie haben Haken in Ihre Software eingabaut, an die wir unsere Programmteile hängen können. In SVN sind das zum Beispiel post- oder pre-commit hooks. Scripte, die bei bestimmten Aktionen ausgeführt werden. Diese können in jeder beliebigen Sprache verfasst sein und dahingehend so ziemlich alles machen, was man sich vorstellen kann.</p>
<h2>Wofür Hooks in Webdiensten?</h2>
<p>Derzeit läuft alles im Netz nach einem ziemlich nervigen Prinzip ab. Im Fachjargon nennt man das <a href="http://de.wikipedia.org/wiki/Pull-Medien">Pull</a>. Für den Laien ist es als das nervige Fragen der kleinen Gören auf dem Weg in den Familienurlaubsort bekannt.</p>
<blockquote><p>Sind wir schon da?</p>
<p style="text-align: right;">Nein!</p>
<p>Sind wir schon da?</p>
<p style="text-align: right;">Nein!</p>
<p>Sind wir schon da?</p>
<p style="text-align: right;">Nein!</p>
<p>Sind wir schon da?</p>
<p style="text-align: right;">Ja, jetzt sind wir da!</p>
</blockquote>
<p>Für beide Seiten wäre es wesentlich entspannter, wenn man nicht ständig nachfragen würde, sondern bescheid gesagt wird, sobald man denn tatsächlich da ist. Und genau das ist das Prinzip der Webhooks. Es wird gepusht, sobald etwas passiert. Dazu hinterlasst man nicht anderes als eine Adresse, hinter der sich ein Script verbirgt, das genau das macht, was man will. Dieses kann in jeder beliebigen Sprache verfasst sein, und somit jede nur erdenkliche Erweiterung für den Service bieten.</p>
<h2>Aber viele Services bieten APIs an! Warum nicht diese benutzen?</h2>
<p>APIs sind in erster Linie dafür gedacht, auf bestimmte Funktionen des Programmes zuzugreifen. Dabei steuern aber auch wir wieder die API an und nicht die API unser Script. Bei Hooks läuft das genau anders herum.  So kann man Hooks also durchaus sinnvoll mit den klassischen APIs kombinieren und die herkömmliche Struktur um ein sinnvolles Feature ergänzen. Hooks sollen APIs also nicht ablösen. Im Gegenteil.</p>
<p><em>Das Foto stammt von <a href="http://www.flickr.com/photos/danieljaeger">Daniel Jaeger</a>.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://phphacker.net/2009/01/13/webhooks-mit-php/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Code-Analyse mit der Reflection-API</title>
		<link>http://phphacker.net/2008/12/20/code-analyse-mit-der-reflection-api/</link>
		<comments>http://phphacker.net/2008/12/20/code-analyse-mit-der-reflection-api/#comments</comments>
		<pubDate>Sat, 20 Dec 2008 18:03:54 +0000</pubDate>
		<dc:creator>Cem Derin</dc:creator>
				<category><![CDATA[Entwicklung]]></category>
		<category><![CDATA[Testing]]></category>

		<guid isPermaLink="false">http://phphacker.net/?p=63</guid>
		<description><![CDATA[PHP5 kommt mit eine schicken Reflection-API daher. Bisher habe ich diese nur sehr selten und wenn auch nur in geringem Umfang benutzt. Da die API allerdings auch DocBlöcke auslesen (leider nicht interpretieren) kann, hat das gute Ding meiner Meinung nach eine ganze Menge Potential. Daher habe ich eine Suite erstellt, mit der sich schnell Source [...]]]></description>
			<content:encoded><![CDATA[<p>PHP5 kommt mit eine schicken Reflection-API daher. Bisher habe ich diese nur sehr selten und wenn auch nur in geringem Umfang benutzt. Da die API allerdings auch DocBlöcke auslesen (leider nicht interpretieren) kann, hat das gute Ding meiner Meinung nach eine ganze Menge Potential. Daher habe ich eine Suite erstellt, mit der sich schnell Source Code analysieren lässt.</p>
<p>Im Endeffekt ist daraus ein kleines Projekt entstanden, mehr dazu am Ende des Artikels.</p>
<p><span id="more-63"></span>Ich habe versucht die Suite so flexibel wie möglich aufzubauen. So ist es möglich einen eigenen Logger zu definieren, der gefundene Regelverstöße auf beliebige Art und Weise festhält. Der Beispiellogger gibt einfach alles direkt aus. So ist es aber auch möglich, Verstöße in einer Datenbank festzuhalten oder in Dateien zu schreiben.</p>
<p>Die Meldungen werden inkl. Datei, Zeile und Autor gespeichert (wenn sich dieser über den DocBlock ermitteln lässt). So sind Verstöße direkt einem Autor zuzuordnen. Als Testregeln habe ich mir folgende ausgedacht:</p>
<ul>
<li>Klassennamen müssen mit Großbuchstaben beginnen</li>
<li>Klassennamen müssen der Ordner- und Dateistruktur unterhalb des Include-Pfads entsprechen</li>
<li>Properties und Methoden im private oder protected scope müssen mit einem Unterstrich beginnen</li>
<li>Jede Klasse, jede Methode und jedes Property muss dokumentiert werden</li>
</ul>
<p>Das erstellen von Regel-Klassen ist recht einfach. An die Methode &#8220;check&#8221; wird die zu checkende reflektierte Klasse übergeben. Der Tester erwartet als Rückgabe entweder &#8220;null&#8221; oder ein Result-Objekt. Ziemlich easy, eigentlich. Schauen wir, ob wir die Testfälle abdecken können.</p>
<h2>Klassennamen müssen mit Großbuchstaben beginnen</h2>
<pre lang="PHP">
<pre class="brush: php">	class Compliance_Rule_Class_Name extends Compliance_Rule  {
		protected $_deficitMessage = &#039;Class name must begin with an upper case letter.&#039;;

		public function check(ReflectionClass $class) {
			$result = null;

			if(!preg_match(&#039;/^[A-Z]/&#039;, $class-&gt;getName())) {
				$result = new Compliance_Rule_Result();
				$message = new Compliance_Rule_Result_Message(
					$class-&gt;getDocComment()-&gt;getAuthor(),
					$class-&gt;getName(),
					new Compliance_Tester_Directory_File($class-&gt;getFileName()),
					$class-&gt;getStartLine(),
					$this-&gt;_deficitMessage
				);
				$result-&gt;addMessage($message);
			}

			return $result;
		}
	}</pre>
</pre>
<p>Schuss und Treffer. Einmal runtergeschrieben funktionierte sofort. Wunderbar. Wir holen uns mit getName den Klassennamen aus der Reflection und prüfen mittels eines regulären Ausdrucks, ob dieser mit einem Großbuchstaben beginnt.</p>
<h2>Klassennamen müssen der Ordner- und Dateistruktur unterhalb des Include-Pfads entsprechen</h2>
<pre lang="PHP">
<pre class="brush: php">	class Compliance_Rule_Class_Path extends Compliance_Rule  {
		protected $_deficitMessage = &#039;Class name must express path to file.&#039;;

		public function check(ReflectionClass $class) {
			$result = null;

			$classname = $class-&gt;getName();
			$path = str_replace(&#039;_&#039;, DIRECTORY_SEPARATOR, $classname). &#039;.php&#039;;
			if(substr($class-&gt;getFileName(), (strlen($path) * -1)) != $path) {
				$result = new Compliance_Rule_Result();
				$message = new Compliance_Rule_Result_Message(
					$class-&gt;getDocComment()-&gt;getAuthor(),
					$class-&gt;getName(),
					new Compliance_Tester_Directory_File($class-&gt;getFileName()),
					$class-&gt;getStartLine(),
					$this-&gt;_deficitMessage
				);
				$result-&gt;addMessage($message);
			}

			return $result;
		}
	}</pre>
</pre>
<p>Wow. Das war genau so einfach! Man könnte diese Regel noch verfeinern, aber in meinem Fall reicht sie voll und ganz aus. Ich wandle den Klassennamen in einen Pfad um, in dem ich die Unterstriche durch die DIRECTORY_SEPERATOR-Konstante ersetze und die Endung &#8220;.php&#8221; hinten dran setze. Dann prüfe ich einfach, ob die Datei, in der sich die reflektierte Klasse befindet von hinten an identisch ist mit dem generierten Pfad. Kommen wir also zur nächsten Regel.</p>
<h2>Properties und Methoden im private oder protected scope müssen mit einem Unterstrich beginnen</h2>
<p>Das habe ich in zwei Regeln aufgeteilt. Und hier bin ich nun auch auf die ersten Probleme gestoßen. Fangen wir also mit einer Regel an, die prüft, ob alle private/protected Properties mit einem Unterstrich beginnen bzw. ob alle mit einem Unterstrich beginnenden Properties private oder protected sind.</p>
<pre lang="PHP">
<pre class="brush: php">	class Compliance_Rule_Class_Property_Name extends Compliance_Rule {
		protected $_deficitMessage = &#039;Protected and public Attributes must begin with an underscore.&#039;;

		public function check(ReflectionClass $class) {

			$result = null;

			foreach($class-&gt;getProperties() as $property) {
				$return = $this-&gt;checkProperty($property);
				if($return !== null) {
					if($result === null) {
						$result = new Compliance_Rule_Result();
					}

					$result-&gt;addMessage($return);
				}
			}

			return $result;
		}

		public function checkProperty(ReflectionProperty $property) {
			if(!$property-&gt;getDeclaringClass()-&gt;isUserDefined()) {
				return;
			}

			if(($property-&gt;isPrivate() OR $property-&gt;isProtected())
					AND
				substr($property-&gt;getName(), 0, 1) != &#039;_&#039;) {
				$message = new Compliance_Rule_Result_Message(
					$property-&gt;getDocComment()-&gt;getAuthor(),
					$property-&gt;getDeclaringClass()-&gt;getName(),
					new Compliance_Tester_Directory_File($property-&gt;getDeclaringClass()-&gt;getFileName()),
					$property-&gt;getLineNumber(),
					$this-&gt;_deficitMessage
				);

				return $message;
			}

			if((!$property-&gt;isPrivate() AND !$property-&gt;isProtected())
					AND
				substr($property-&gt;getName(), 0, 1) == &#039;_&#039;) {
				$message = new Compliance_Rule_Result_Message(
					$property-&gt;getDocComment()-&gt;getAuthor(),
					$property-&gt;getDeclaringClass()-&gt;getName(),
					new Compliance_Tester_Directory_File($property-&gt;getDeclaringClass()-&gt;getFileName()),
					$property-&gt;getLineNumber(),
					$this-&gt;_deficitMessage
				);

				return $message;
			}
		}
	}</pre>
</pre>
<p>Zu unserem Problem: Um den Dateinamen in das Result-Objekt eintragen zu können muss ich mir zunächst wieder die Überklasse holen. Haben wir hier nun aber ein Property dass innerhalb einer Standard-PHP-Klasse definiert wurde, von einer erweiterten Klasse übernommen wurde und nicht unserer Regel entspricht, haben wir keinen Dateinamen. So oder so sind das Verstöße, gegen die man sich (als PHP-Entwickler) nicht wehren kann.</p>
<p>Hier dann noch die Regel für Methoden</p>
<pre lang="PHP">
<pre class="brush: php">	class Compliance_Rule_Class_Method_Name extends Compliance_Rule {
		protected $_deficitMessage = &#039;Protected and private methods must begin with an underscore.&#039;;

		public function check(ReflectionClass $class) {
			$result = null;

			foreach($class-&gt;getMethods() as $method) {
				$return = $this-&gt;checkMethod($method);
				if($return !== null) {
					if($result === null) {
						$result = new Compliance_Rule_Result();
					}

					$result-&gt;addMessage($return);
				}
			}

			return $result;
		}

		public function checkMethod(ReflectionMethod $method) {
			if(!$method-&gt;getDeclaringClass()-&gt;isUserDefined()) {
				return;
			}

			if(($method-&gt;isPrivate() OR $method-&gt;isProtected())
					AND
				substr($method-&gt;getName(), 0, 1) != &#039;_&#039;) {
				$message = new Compliance_Rule_Result_Message(
					$method-&gt;getDocComment()-&gt;getAuthor(),
					$method-&gt;getDeclaringClass()-&gt;getName(),
					new Compliance_Tester_Directory_File($method-&gt;getDeclaringClass()-&gt;getFileName()),
					$method-&gt;getStartLine(),
					$this-&gt;_deficitMessage
				);

				return $message;
			}
		}
	}</pre>
</pre>
<p>Ich habe hier den eigentlichen Check gegen die Regel in eine weitere Methode ausgelagert. Das hat einen ziemlich einfachen Grund: Ich bin faul. Ich kann in der neuen Methode Type Hinting auf die Properties/Methoden machen und kann so mein Auto-Complete in Eclipse benutzen. <img src='http://phphacker.net/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<h2>Jede Klasse, jede Methode und jedes Property muss dokumentiert werden</h2>
<p>Im Grunde ist das nun auch nur eine Zusammenführung von dem, was wir in den Regeln zuvor schon gemacht haben. Hier der Code:</p>
<pre lang="PHP">
<pre class="brush: php">	class Compliance_Rule_Class_Documentation extends Compliance_Rule  {
		protected $_deficitMessage = &#039;All classes, methods and attributes must be documentated.&#039;;

		public function check(ReflectionClass $class) {
			$result = null;

			if(($return = $this-&gt;checkClass($class)) !== null) {
				if($result === null) {
					$result = new Compliance_Rule_Result();
				}

				$result-&gt;addMessage($return);
			}

			foreach($class-&gt;getMethods() as $method) {
				$return = $this-&gt;checkMethod($method);
				if($return !== null) {
					if($result === null) {
						$result = new Compliance_Rule_Result();
					}

					$result-&gt;addMessage($return);
				}
			}

			foreach($class-&gt;getProperties() as $property) {
				$return = $this-&gt;checkProperty($property);
				if($return !== null) {
					if($result === null) {
						$result = new Compliance_Rule_Result();
					}

					$result-&gt;addMessage($return);
				}
			}

			return $result;
		}

		public function checkMethod(ReflectionMethod $method) {
			if(!$method-&gt;getDeclaringClass()-&gt;isUserDefined()) { return; }

			if($method-&gt;getDocComment()-&gt;__toString() == &#039;&#039;) {
				$message = new Compliance_Rule_Result_Message(
					$method-&gt;getDocComment()-&gt;getAuthor(),
					$method-&gt;getDeclaringClass()-&gt;getName(),
					new Compliance_Tester_Directory_File($method-&gt;getDeclaringClass()-&gt;getFileName()),
					$method-&gt;getStartLine(),
					$this-&gt;_deficitMessage. &#039; method&#039;
				);

				return $message;
			}
		}

		public function checkProperty(ReflectionProperty $property) {
			if(!$property-&gt;getDeclaringClass()-&gt;isUserDefined()) { return; }

			if($property-&gt;getDocComment()-&gt;__toString() == &#039;&#039;) {
				$message = new Compliance_Rule_Result_Message(
					$property-&gt;getDocComment()-&gt;getAuthor(),
					$property-&gt;getDeclaringClass()-&gt;getName(),
					new Compliance_Tester_Directory_File($property-&gt;getDeclaringClass()-&gt;getFileName()),
					$property-&gt;getLineNumber(),
					$this-&gt;_deficitMessage. &#039; property&#039;
				);

				return $message;
			}
		}

		public function checkClass(ReflectionClass $class) {
			if($class-&gt;getDocComment()-&gt;__toString() == &#039;&#039;) {
				$message = new Compliance_Rule_Result_Message(
					$class-&gt;getDocComment()-&gt;getAuthor(),
					$class-&gt;getName(),
					new Compliance_Tester_Directory_File($class-&gt;getFileName()),
					$class-&gt;getStartLine(),
					$this-&gt;_deficitMessage. &#039; class&#039;
				);

				return $message;
			}
		}
	}</pre>
</pre>
<h2>Probleme</h2>
<p>Wer bis hierhin aufgepasst hat, wird festgestellt haben, dass Zeilennummern von Properties sich nicht über die Reflection ermitteln lassen. Auch der Autor ist noch nicht automatisiert aus dem DocBlock auszulesen. Hier sind leider ein paar Erweiterungen der Reflection-API notwendig. Glücklicherweise kann man die Reflection-Klassen problemlos extenden. Bauen wir uns also zunächst eine Möglichkeit um die Zeilennummer eines Properties zu ermitteln. Auf Anhieb fiel mir nichts besseres ein, als die Datei, in der sich die Klasse befindet auszulesen. Aber auch hier wieder direkt zwei Probleme: Was, wenn sich in einer Datei zwei Klassen befinden, die beide ein Property mit dem selben Namen und den selben Eigenschaften besitzen? Und dazu kommt dann noch das Dilemma, dass man protected/private/public und static in beliebiger Reihenfolge notieren kann. Wird also doch nicht so einfach.</p>
<h2>Reflection-API ergänzen: Zeilennummern von Properties ermitteln</h2>
<p>Zunächst der Code, den ich benutzt habe:</p>
<pre lang="PHP">
<pre class="brush: php">		public function getLineNumber() {
			$file = $this-&gt;getDeclaringClass()-&gt;getFileName();
			$startLine = $this-&gt;getDeclaringClass()-&gt;getStartLine();
			$endLine = $this-&gt;getDeclaringClass()-&gt;getEndLine();

			$contents = file_get_contents($file);
			$contents = explode(&quot;\n&quot;, $contents);

			$classCode = &#039;&#039;;

			for($i = $startLine -1; $i &lt; $endLine; $i++) {
				$classCode.= $contents[$i]. &quot;\n&quot;;
			}

			$pattern = $this-&gt;_getPattern();

			$replaced = preg_replace($pattern, &#039;START_LINE_COMPLIANCE$1END_LINE_COMPLIANCE&#039;, $classCode);

			$classCode = explode(&quot;\n&quot;, $replaced);

			foreach($classCode as $lineNumber =&gt; $line) {
				if(substr(trim($line), 0, strlen(&#039;START_LINE_COMPLIANCE&#039;)) == &#039;START_LINE_COMPLIANCE&#039;) {
					$startLineProperty = $lineNumber + $startLine;
				}

				if(substr(trim($line), (strlen(&#039;END_LINE_COMPLIANCE&#039;) * -1)) == &#039;END_LINE_COMPLIANCE&#039;) {
					$endLineProperty = $lineNumber + $startLine;
				}

			}

			return $startLineProperty;
		}</pre>
</pre>
<p>Zunächst ermittle ich die Datei, in der sich die Klasse befindet und die Start- und Endzeile, zwischen der sie definiert wird. Ich lese die Datei aus, packe die Zeilen in Arrayelemente und baue mir ein neues nur aus den Zeilen, in der sich die Klasse befindet. Diese führe ich wieder als einen zusammenhängenden Text zusammen und suche nach einem Ausdruck, den ich mit Schlüsselwörtern ergänze. So kann ich die Zeile ermitteln, berücksichtige das Offset und gebe das ganze aus.</p>
<p>Wie der Ersetzungsausdruck generiert wird erspare ich euch, das ist einfach nur langweilig <img src='http://phphacker.net/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> . Wen es doch interessiert, der kann im Source nachsehen.</p>
<p>Jetzt fragen sich sicherlich einige, warum ich einige Sachen nicht anders/einfacher gelöst habe:</p>
<h3>Warum nicht fopen/fread?</h3>
<p>Das Problem bei fread ist, dass es entweder eine Menge an Bytes einliest oder bis zum Zeilenende. Da wir tatsächlich Zeilen brauchen, bringt uns eine Menge Bytes überhaupt nichts. Je nach kodierung der Quelldatei liest fread einfach mal die komplette Datei (bzw. bis zur maximalen Byte-Grenze) ein, und glaubt, das war nun eine Zeile. Unbrauchbar also.</p>
<h3>Warum nicht direkt die Array-Elemente nach dem Property durchsuchen?</h3>
<p>Es könnte durchaus möglich sein, dass das Property über mehrere Zeilen definiert wurde. Ich entschloss mich daher, das Property zu markieren um später die Anfangs und Endzeile ermitteln zu können. Das war insofern erst einmal vergebene Liebesmüh, weil ich es derzeit nichtmal ausgeben <img src='http://phphacker.net/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<h2>DocBlock-Object</h2>
<p>Hier habe ich mich bei Martin Kuckert bedient, der vor einiger Zeit eine DocParser-Klasse geschrieben hat. Die Methode &#8220;getDocComment&#8221; gibt also keinen String mehr zurück, sondern liefert ein DocBlock-Objekt. Dieses hat, in meiner Fassung, derzeit nur die Methode &#8220;getAuthor&#8221; implementiert.</p>
<p>Aber: Wir haben in unserem Regelset ja die Anweisung, dass alles Dokumentiert sein muss. Ist etwas nun nicht dokumentiert, so kann man auch schlecht einen Autor aus dem DocBlock ermitteln. Aus diesem Grund gibt es den Parameter &#8220;assume&#8221;, der standardmäßig auf true ist. Damit kann man den Author &#8220;vermuten&#8221;. Das Prinzip ist simple: Ist ein Property oder eine Methode nicht dokumentiert, so wird der DocBlock der Klasse genommen.</p>
<h2>Let&#8217;s roll</h2>
<p>Nachdem ich die Suite gegen sich selbst rennen ließ, wurde mir klar, dass ich selbst noch ein paar Kommentare schreiben muss. Das sagt mir direkt, dass das nicht ganz unnützlich ist, ein solches Tool in der Hinterhand zu haben.</p>
<h2>Das Projekt</h2>
<p>Ich habe jetzt ein paar Tage mit der Test Suite und den Regeln verbracht und habe richtig Spaß daran gehabt. Ich habe die Test-Suite gegen das Zend Framework testen lassen und bin über ein paar Fallstricke gestolpert &#8211; allen vorran das Memory Limit. Daher habe ich mich beim schreiben der letzten Absätze dazu entschlossen das ganze als Projekt weiterzuverfolgen. Daher hier <a href="http://phphacker.net/compliance/">eine kleine Projektseite für den Compliance Suite</a>. Dort könnt ihr das ganze auch runterladen und selbst mal ausprobieren.</p>
]]></content:encoded>
			<wfw:commentRss>http://phphacker.net/2008/12/20/code-analyse-mit-der-reflection-api/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
