Seite wählen

NETWAYS Blog

PHP Arrays filtern, Improved

Jeder der schonmal mit PHP in Berührung kam kennt vermutlich array_filter. Dieses kleine Schmuckstück ist manchmal ganz praktisch, kann jedoch nicht mit assoziativen Arrays umgehen. Die PHP SPL bietet jedoch seit Version 5.1 eine nette Alternative: Den FilterIterator
mehr lesen…

Johannes Meyer
Johannes Meyer
Lead Developer

Johannes ist seit 2011 bei uns und inzwischen, seit er 2014 die Ausbildung abgeschlossen hat, als Lead Developer für Icinga Web 2, Icinga DB Web sowie alle möglichen anderen Module und Bibliotheken im Web Bereich zuständig. Arbeitet er gerade mal nicht, macht er es sich bei schlechtem Wetter am liebsten zum zocken oder Filme/Serien schauen auf dem Sofa gemütlich. Passt das Wetter, geht's auch mal auf eines seiner Zweiräder. Motorisiert oder nicht.

Mocks und Stubs mit Mockery

Heute möchte ich euch das PHP-Framework „Mockery“ vorstellen. Wie dessen Name und der Titel dieses Blog-Post schon vermuten lassen, ist es damit möglich Mocks und Stubs (im Folgenden nur noch „Mock“) in/für PHP zu erstellen. Mockery arbeitet prinzipiell wunderbar mit z.B. PHPUnit zusammen und kollidiert nicht mit anderen Frameworks, jedoch gibt es gerade in dieser Kombination, für einen erfolgreichen Einsatz, einiges zu beachten.
Mit Mockery können fünf verschiedene Arten von Mocks erstellt werden. Die einfachste Art sind Mocks ohne Bezug zu jeglichen bereits existierenden Code-Bestandteilen. Mocks können jedoch auch von einem bestimmten Typ sein, sei es nun eine konkrete bzw. abstrakte Klasse oder ein Interface. Da Mocks standardmäßig alle Methoden einer Klasse maskieren, kann man sie als „partielle“ Mocks deklarieren wodurch nur ganz bestimmte Methoden maskiert werden. Statische Methoden und sogar Instanziierungen können mit Hilfe von „Alias-Mocks“ gemocked werden, sofern auto loading genutzt wird und die eigentlichen Klassen noch nicht geladen wurden. Selbst bereits existierende Mocks können erweitert werden und erben so alle Eigenschaften des Basis-Mocks.
Damit Mocks aber überhaupt erst sinnvoll verwendet werden können, muss definiert werden wie diese verwendet werden. Dies geschieht mit sogenannten „Expectations“. Eine solche Expectation besteht aus mindestens einem Methoden-Namen und optional ein oder mehreren Argument-Validatoren. Diese Validatoren bestimmen wie die Argumente, die die Methode erwartet, auszusehen haben. Entspricht etwas nicht den Erwartungen wird eine Ausnahme geworfen, was im Falle von PHPUnit zu einem fehlgeschlagenen Test führt.
Selbstverständlich kann man auch das Verhalten eines Mocks, mit sogenannten „Behaviour modifiers“, beeinflussen. Ob ein bestimmter Wert zurückgegeben, eine bestimmte Ausnahme geworfen, eine bestimmte Eigenschaft gesetzt oder die Methode nur eine bestimmte Anzahl oft (Nie?) aufgerufen werden soll, alles kein Problem für Mockery.
Ein besonders tolles Feature von Mockery, sind die „Demeter Chains“. Hiermit lassen sich fluid interfaces auf sehr einfache Art und Weise mocken:

$fritz = Mockery::mock(‚FischersFritz‘);
$fritz->shouldReceive(‚fischt->frische->fische‘);
$fritz->fischt()->frische()->fische();

Zu beachten ist hier, dass diese Form der Expectation nicht kompatibel mit der Methode getMock() ist:

// getMock() gibt nicht den Mock zurück. Dies ist leider kein bug.
$fritz = Mockery::mock(‚SomeFritz‘)->shouldReceive(‚fischt->frische->fische‘)->getMock();

Mockery hat jedoch auch seine Kehrseiten. So ist es z.B. inkompatibel mit dem Feature „backupStaticAttributes“ von PHPUnit, kann keine Mocks mit Zuständen und keine multiplen „Demeter Chains“ abbilden. Außerdem ist man z.T. gezwungen das „runInSeparateProcess“ Feature von PHPUnit zu verwenden, wenn man „Alias-Mocks“ einsetzt.
Im Großen und Ganzen bin ich sehr zufrieden mit Mockery, setze es gerne ein und kann es nur weiter empfehlen. Da ich allerdings nicht die vollständige Funktionalität von Mockery vorgestellt habe, lege ich jedem ans Herz einen Blick in die doch sehr umfangreiche und übersichtliche Dokumentation zu werfen.

Johannes Meyer
Johannes Meyer
Lead Developer

Johannes ist seit 2011 bei uns und inzwischen, seit er 2014 die Ausbildung abgeschlossen hat, als Lead Developer für Icinga Web 2, Icinga DB Web sowie alle möglichen anderen Module und Bibliotheken im Web Bereich zuständig. Arbeitet er gerade mal nicht, macht er es sich bei schlechtem Wetter am liebsten zum zocken oder Filme/Serien schauen auf dem Sofa gemütlich. Passt das Wetter, geht's auch mal auf eines seiner Zweiräder. Motorisiert oder nicht.

VMware tools auf einem FreeBSD6-8 Gast installieren

Vor einiger Zeit wurde ich genötigt die VMware tools auf einem FreeBSD Gast, der Teil eines ESXi bare-metal Hypervisors ist, zu installieren. Der erste naive Versuch, das Image zu mounten und die Installation anzustoßen, schlug natürlich gnadenlos fehl. Danach begann die Suche nach einer Lösung, die nach einer gefühlten Ewigkeit und mehreren kläglichen Versuchen dann doch noch zum Erfolg führte.
mehr lesen…

Johannes Meyer
Johannes Meyer
Lead Developer

Johannes ist seit 2011 bei uns und inzwischen, seit er 2014 die Ausbildung abgeschlossen hat, als Lead Developer für Icinga Web 2, Icinga DB Web sowie alle möglichen anderen Module und Bibliotheken im Web Bereich zuständig. Arbeitet er gerade mal nicht, macht er es sich bei schlechtem Wetter am liebsten zum zocken oder Filme/Serien schauen auf dem Sofa gemütlich. Passt das Wetter, geht's auch mal auf eines seiner Zweiräder. Motorisiert oder nicht.

There is a shovel here.

Brandneu, gräbt Antiquitäten aus und ist äußerst schmackhaft!
Wer auch sone dolle Schaufel haben möchte, besorgt sich mit seiner bevorzugten Paket-Verwaltung emacs und tippt auf seinem Linux/OSX System folgendes in die Kommandozeile:
emacs -batch -l dunnet
Viel Spaß! 🙂

Johannes Meyer
Johannes Meyer
Lead Developer

Johannes ist seit 2011 bei uns und inzwischen, seit er 2014 die Ausbildung abgeschlossen hat, als Lead Developer für Icinga Web 2, Icinga DB Web sowie alle möglichen anderen Module und Bibliotheken im Web Bereich zuständig. Arbeitet er gerade mal nicht, macht er es sich bei schlechtem Wetter am liebsten zum zocken oder Filme/Serien schauen auf dem Sofa gemütlich. Passt das Wetter, geht's auch mal auf eines seiner Zweiräder. Motorisiert oder nicht.

coverage.py in Jenkins integrieren

Nachdem bereits letzte Woche Gunnar etwas zu code coverage geschrieben hat werde ich jetzt noch einmal nachlegen, mich jedoch auf coverage.py und dessen Nutzung sowie die Integration in Jenkins beschränken.
Was ist coverage.py?
coverage.py ist ein Tool um für in Python geschriebenen Quellcode coverage reports zu generieren. Aber zuerst einmal müssen ein paar Informationen generiert werden, damit überhaupt irgendetwas visuell dargestellt werden kann:
coverage run python-script
Reports werden dann folgendermaßen generiert:
coverage report # Text-basierter Report in der Konsole
coverage html -d ziel-verzeichnis # html Report mit im Quellcode hervergehobenen Zeilen
coverage xml -o xml-datei # xml Report für die Weiterverarbeitung in anderen Systemen
Das ganze geht natürlich auch in Verbindung mit nosetests. Details dazu könnt ihr hier finden.
Integration in Jenkins
Um nun coverage reports in Jenkins für das eigene Projekt zu generieren greifen wir selbstverständlich auf coverage.py zurück. Um das zu realisieren bietet sich „Execute shell“ als build step an in welchem wir oben angegebene Befehle ausführen lassen:
coverage run python-script
coverage xml # Output landet per default in coverage.xml
Dann legt man eine post-build action an, die sich „Publish Cobertura Coverage Report“ nennt und gibt dort bei „Cobertura xml report pattern“ den Pfad zu der vom build step generierten xml Datei an. (**/coverage.xml, falls die Datei direkt im workspace liegt.)
Soweit so gut. Wenn nun ein Build ausgeführt wird, hat man am Ende einen coverage report in Jenkins, der jedoch keinerlei Details dazu aufführt welche Zeilen im Quellcode denn nun genau betroffen sind. Zu beurteilen woran das liegt, maße ich mir hier einfach mal nicht an und gebe nur einen kleinen Hinweis wie dieses Problem mit einer kleinen Erweiterung des build steps zu lösen ist:
sed -i -e 's??ein/relativer/pfad/zum/quellcode?' coverage.xml
sed -i -e 's?filename="'$WORKSPACE'/ein/relativer/pfad/zum/quellcode/?filename="?' coverage.xml
Wobei hier „ein/relativer/pfad/zum/quellcode“ zu ersetzen ist. Zu beachten ist hierbei, dass es sich tatsächlich um einen relativen Pfad handeln muss, ausgehend vom workspace. Beim nächsten Build gibts dann auch hervorgehobene Zeilen im Quellcode. 🙂
Zu guter letzt noch ein Protip:
Um coverage.py dazu zu bringen branch coverage (conditionals usw.) zu messen muss eine spezielle Option angegeben werden:
coverage run --branch python-script
Damit das auch mit nosetests funktioniert, bedarf es erneut eines kleinen Tricks:
touch .coveragerc
echo "# .coveragerc to control coverage.py\n\n[run]\nbranch=True" > .coveragerc
Das muss im selben Verzeichnis ausgeführt werden in dem auch coverage.py selbst ausgeführt werden wird.
Und nun viel Spaß mit den vielen bunten Trends und Quellcodes! 😀

Johannes Meyer
Johannes Meyer
Lead Developer

Johannes ist seit 2011 bei uns und inzwischen, seit er 2014 die Ausbildung abgeschlossen hat, als Lead Developer für Icinga Web 2, Icinga DB Web sowie alle möglichen anderen Module und Bibliotheken im Web Bereich zuständig. Arbeitet er gerade mal nicht, macht er es sich bei schlechtem Wetter am liebsten zum zocken oder Filme/Serien schauen auf dem Sofa gemütlich. Passt das Wetter, geht's auch mal auf eines seiner Zweiräder. Motorisiert oder nicht.