PHP: header() mocken, um Controller zu Unit-testen

2011 habe ich eine Technik vorgestellt, Funktionen in PHP Unit Tests zu mocken, die sich die Regeln für Namensauflösung von PHP namespaces zunutze macht. Er kann hier gelesen werden:

Es macht mich stolz, dass der große Matthew Weier O’Phinney 1 nun die selbe Technik beschreibt, um Code zu testen, der Ausgaben erzeugt, insbesondere Code, der HTTP Header mit der Core-Funktion header() sendet. Lies mehr dazu in seinem Artikel:

Meiner Meinung nach ist das ein großartiges Beispiel dafür, wie nützlich diese Methode ist. “Headers already sent” Fehler in Unit Tests können einen in den Wahnsinn treiben. Unglücklicherweise gibt es immer noch viele Anwendungen, die keine Namespaces nutzen (*hust* Magento *hust*), dort funktioniert die Methode nicht.

Notes:

  1. für die, die ihn nicht kennen: Er ist Zend Framework Project Lead und Du solltest seinem Blog auf http://mwop.net/blog.html folgen!

Magento Testing: Formulare mit einem Klick ausfüllen

Wer kennt es nicht: Beim manuellen Testen von Funktionen wie dem Checkout als Gast müssen jedes Mal mühsam alle Formularfelder ausgefüllt werden. Mit Chrome Autocomplete oder “test”, Strg + C, Strg + V geht das noch einigermaßen schnell, nervt aber immer noch ein wenig. Und was, wenn die Testdaten noch einigermaßen sinnvoll sein sollen und nicht jedes Mal gleich?

Inspiriert von diesem Artikel auf css-tricks.com habe ich ein kleines Magento-Modul entwickelt, das das Ausfüllen von Magento-Formularen mit Dummy-Daten mit einem Mausklick ermöglicht. Aktuell implementiert ist es für Rechnungsadresse und Versandadresse.

Hier geht es zum Github-Repository: SSE_FormFiller

Und so sieht es aus:

Screenshot: Formulare im Checkout

Konfiguration

Continue reading “Magento Testing: Formulare mit einem Klick ausfüllen”

Formular-Probleme nach auf Magento Update auf CE 1.8.1 oder EE 1.13.1 (Login, Warenkorb)

Wenn nach einem Magento Update auf CE 1.8.1 oder EE 1.13.1 die Login-Formulare im Frontend nicht mehr funktionieren, muss das genutzte Theme aktualisiert werden. Die Formulare benötigen nun einen Form Key, fehlt dieser schlägt die Validierung im Controller fehl. Das selbe gilt für den “Warenkorb aktualisieren” Button in cart.phtml. Wie das gefixt werden kann, siehe hier:


http://blueclawecommerce.co.uk/blog/fix-customer-cannot-login-to-magento-1-8-1/

Optimal ist natürlich, wenn das Theme so wenig wie möglich an Core-Templates überschreibt und Änderungen weitestgehend mit Layout-Updates in [theme]/local.xml und CSS vornimmt.

Unit-testen von generierten PDFs mit PHPUnit und PDFBox

Zu den Features, die sich nicht leicht mit Unit Tests prüfen lassen gehört das generieren von PDF-Dateien.

Hilfreich dazu ist das Kommandozeilen-Tool PDFBox mit der Option ExtractText:

PDF

This application will extract all text from the given PDF document.

Das erlaubt uns schon mal, den Text-Inhalt des Dokuments zu testen oder nach bestimmten Strings darin zu suchen.

Interessant wird es mit der Option -html, die das PDF zu HTML konvertiert. Damit sind auch Struktur und Formatierungen ansatzweise testbar.

Leider arbeitet das Tool nicht mit Streams, wir müssen also temporäre Dateien nutzen. Ein einfaches Beispiel für eine Funktion, die ein PDF Dokument als String entgegennimmt, mit PdfBox in HTML konvertiert und das HTML als String zurückgibt:

/**
 * @var string $streamIn binary string with generated PDF
 * @return string HTML string
 */
function htmlFromPdf($streamIn)
{
  $pdf = tempnam();
  file_put_contents($pdf, $streamIn);
  $txt = tempnam();
  exec('java -jar pdfbox-app-x.y.z.jar ExtractText -encoding UTF-8 -html ' . $pdf . ' ' . $txt);
  $streamOut = file_get_contents($txt);
  unlink($pdf);
  unlink($txt);
  return $streamOut;
}

Für Regressionstests oder beim Refaktorisieren kann es mitunter ausreichen, zu testen, dass das generierte PDF sich gegenüber dem Referenz-Dokument nicht geändert hat. Hier bietet sich ein Hash an, die Datei selbst ist aber – vermutlich aufgrund von Timestamps – nicht bei jedem Durchlauf exakt gleich. Ein Hash des nach HTML konvertierten Dokuments dagegen genügt:

        // In PHPUnit test case:
        $converter = new PdfBox();
        $html = $converter->htmlFromPdfStream($pdf);
        $this->assertEquals('336edd9ee49b57e6dba5dc04602765056ce05b91', sha1($html), 'Hash of PDF content');

Continue reading “Unit-testen von generierten PDFs mit PHPUnit und PDFBox”

Relaunch 2014

Sie betrachten gerade meine neu gestaltete Webseite. Nach einigen Jahren mit Habari als Blog-Software bin ich nun doch auf WordPress umgestiegen. Man kann von der Code-Basis ja halten was man will, die Bedienung ist extrem komfortabel und das Angebot an Erweiterungen riesig. Außerdem gibt es kaum eine Möglichkeit, schneller eine ansprechende Webseite nach dem Stand der Technik in Sachen HTML+CSS fertigzustellen.

Alle Beiträge aus dem Blog habe ich übernommen und mit dem Simple 301 Redirects Plugin dafür gesorgt, dass die alten URLs noch funktionieren. Die Kommentare sind dabei allerdings leider auf der Strecke geblieben.

Das Blog wird sich weiterhin mit technischen Themen befassen, vor allen Dingen rund um PHP und Magento-Entwicklung. Außerdem habe ich die Formatvolagen “Kurzmitteilung” und “Link” für mich entdeckt, die werde ich wohl noch öfter nutzen; genau das richtige für schreibfaule Menschen wie mich. So wird hoffentlich trotzdem einiges an interessantem Inhalt zustandekommen.

Nach dem “weiterlesen”-Link gibt es ein paar technische Details für die, die es interessiert:
Continue reading “Relaunch 2014”

PHP: Referenzen und Speicher

Nutze niemals Referenzen in PHP, nur um Speicherbedarf zu reduzieren. PHP handhabt das bereits mit seinem internen copy on write Mechanismus.

Beispiel:

$a = str_repeat('x', 100000000); // Memory used ~ 100 MB
$b = $a;                         // Memory used ~ 100 MB
$b = $b . 'x';                   // Memory used ~ 200 MB

Du solltest Referenzen nur nutzen, wenn Du genau weißt, was du tust und sie für Funktionalität benötigst. Das ist fast nie der Fall, so dass man sie auch getrost völlig ignorieren kann. PHP-Referenzen sind im Allgemeinen eigenwillig und können in unerwartetem Verhalten resultieren.

Frage und Antwort auf StackOverflow