RWTH Aachen • Web-Entwicklung seit 2005 • Schwerpunkt auf Magento seit 2011 • integer_net GmbH seit 2014 • Verheiratet, zwei Kinder Fabian Schmengler – Pragmatisches Unit Testing 4
isoliert testen • Integration Test – White Box: Zusammenspiel von Komponenten testen • System Test – Black Box: Funktionaler Test des Gesamtsystems Fabian Schmengler – Pragmatisches Unit Testing 6
Schreibe die minimale Implementierung, die den Test erfolgreich macht 3. Wiederhole (1) und (2) bis Feature komplett 4. Refaktorisiere bis Code sauber Fabian Schmengler – Pragmatisches Unit Testing 7
(M * K) (zusätzlich gefundene Bugs) / (nicht gefundene Bugs) • L = Lebenszeit (Anzahl Durchläufe bis Test veraltet) • W = Wahrscheinlichkeit, neue Bugs zu finden (Erwartungswert für Bugs pro Durchlauf) • M = Bugs/Zeit, die beim manuellen Testen gefunden werden können • K = Kosten (Zeit für die Test-Implementierung) Sind automatisierte Tests wirklich zu teuer? Mit dieser Formel lässt es sich prüfen! Fabian Schmengler – Pragmatisches Unit Testing 8
is mostly unrelated to the specific purpose for which it was written. It's the accidental things that count: the untargeted bugs that it finds – Brian Marick Fabian Schmengler – Pragmatisches Unit Testing 9
– Falscher Alarm bei Feature-Änderung – Geringe Wahrscheinlichkeit, Fehler durch Nebeneffekte zu finden • Ohne Integrationstests kontraproduktiv – Vorgegaukelte Sicherheit! Fabian Schmengler – Pragmatisches Unit Testing 12
Test erfolgreich zu machen, zwingt uns zu möglichst vollständigen Testdaten Fabian Schmengler – Pragmatisches Unit Testing 15 function testFaculty() { assert('faculty(1)===1'); assert('faculty(2)===2'); assert('faculty(3)===6'); } function faculty($n) { return $n; }
entwickelt • Testbarkeit war also nie Qualitätskriterium • Isoliertes Testen von Modulen ist schwer – Zu viele Abhängigkeiten • Systemtests (z.B. Selenium) sind langsam – Laufzeit bei komplett durchgetestetem Shop > 1h – Kein direktes Feedback – Keine testgetriebene Entwicklung möglich Fabian Schmengler – Pragmatisches Unit Testing 17
der Magento Welt salonfähig gemacht – Fixtures – Mocks für Models, Helpers – Controller Tests mit Session Simulation – Tests für Layouts und Konfigurationen • Vielseitig ABER naturgemäß komplex und fehleranfällig Fabian Schmengler – Pragmatisches Unit Testing 19
oder Observer? – Ist das Model vollständig geladen? – Was steht in der Session? – Was wird aus der Registry geholt? • Aufwändiges Mocking notwendig • Bugs entstehen am ehesten, weil die Parameter nicht wie erwartet sind. Der Unit Test in seiner heilen Mock- Welt bekommt das nicht mit. • Isoliertes Testen für die meisten Magento-Anpassungen sinnlos Fabian Schmengler – Pragmatisches Unit Testing 20
• Controller Tests => Integrationstests • Anpassungen von Magento mit mehr Support Code als Feature Code => Integrationstests • Auswirkung von Konfigurationen => Integrationstests • Tests mit EcomDev_PHPUnit sind in den meisten Fällen keine Unit Tests! Fabian Schmengler – Pragmatisches Unit Testing 22
Alternativ PHPUnit mit eigener Bootstrap- Datei – Testen gegen verschiedene Magento Versionen mit Travis CI und Aoe Mage Test Stand • Für Shops: – xtest Fabian Schmengler – Pragmatisches Unit Testing 23
Interaktion zu Magento • PRO Tipp: Logik komplett von Magento entkoppeln und nur mit PHPUnit testen – Schnelle Testdurchläufe – Saubererer Code – Portierung zwischen Magento 1 und Magento 2 möglich Fabian Schmengler – Pragmatisches Unit Testing 24
nach Lagerbestand der Einzelstücke • Komplexe Business-Logik – Nicht völlig entkoppelt von Magento aber überschaubare Abhängigkeit • Hohes Risiko von Bugs und Nebeneffekten – angepasster Bündel-Produkttyp – Rewrites von essentiellen Magento Models Fabian Schmengler – Pragmatisches Unit Testing 25 Beispiel 1
(200g + 200g) • Menge für die gerade noch eine exakte Kombination möglich ist • n+1 • Menge für die gerade noch eine Kombination mit Gewicht-Toleranz möglich ist • n+1 • Maximal anfragbare Menge (10000) Fabian Schmengler – Pragmatisches Unit Testing 27 Beispiel 1
Testdaten und Testcode separiert • Später Integrationstests mit gleichen Testdaten • Bei Bugs und Change Requests, Testdaten erweitert Fabian Schmengler – Pragmatisches Unit Testing 28 Beispiel 1
für: – Sequentielle Bestellung einzelner Pakete – Bestellungen mehrerer Pakete auf einmal – Neuberechnung nach Lagerbestand-Änderung • … und benutzt für Integrationstests im Kontext: – In den Warenkorb legen – Zusätzliche Menge in den Warenkorb legen – Menge im Warenkorb aktualisieren – Gesamten Warenkorb aktualisieren Fabian Schmengler – Pragmatisches Unit Testing 29 Beispiel 1
schreiben, der die Daten aus der Fixture prüft – z.B. bei Bündelprodukten mit EcomDev_PHPUnit • Tests für alle möglichen Grenzfälle sind bei instabilem Code unverzichtbar – Instabil sind z.B.: viele Rewrites, viele Features die voneinander abhängen Fabian Schmengler – Pragmatisches Unit Testing 30 Beispiel 1
aus Faker • Berücksichtigt Assoziationen order address == customer address => dummy order address == cummy customer address • Logik als eigenständige Bibliothek (in lib/) • Magento-Modul implementiert nur Interfaces zum lesen und schreiben von Daten und delegiert an die Bibliothek Fabian Schmengler – Pragmatisches Unit Testing 31 Beispiel 2
• Test der Geschäftslogik – z.B. gleiche Eingabe => gleiche Ausgabe wenn der selbe Kunde assoziiert ist, sonst nicht. • Hier können Testdaten effizient variiert werden um Sonderfälle abzudecken • Testlaufzeit 150 ms (keine Datenbankzugriffe, keine Magento-Instantiierung) Fabian Schmengler – Pragmatisches Unit Testing 33 Beispiel 2
• Bridge Test: Geben die Bridge Implementierungen die korrekten Attribut-Werte zurück und funktioniert das setzen neuer Werte? • Anonymizer Test: Werden alle Daten tatsächlich verändert? • Beschränkung auf wenige Durchläufe, keine ausführlichen Testdaten notwendig • Testlaufzeit: 4 s Fabian Schmengler – Pragmatisches Unit Testing 34 Beispiel 2
sie sinnvoll ohne Magento modelliert werden kann (Feature Code > Support Code)? Dann lohnt sich das Entkoppeln! • Bridge Pattern zur Anbindung an Magento • TDD und Unit Tests für Library, Integrationstest für Magento-Modul • Unit Tests mit PHPUnit 4.5, Mutation Testing mit Humbug zur Verbesserung der Tests Fabian Schmengler – Pragmatisches Unit Testing 35 Beispiel 2
nicht zwingend notwendig – xtest verbindet beides (via PHPUnit_Selenium) • Smoke Tests – Durchlaufen der Basis-Shop-Funktionalität, um gravierende Fehler zu entdecken • Selenium IDE (Firefox Plugin) – Für kurzlebige Tests super, auch während der Entwicklung – Für Regressionstests zu unzuverlässig Fabian Schmengler – Pragmatisches Unit Testing 36
– Werkzeug, nicht Ziel! – Code Coverage kann ungetesteten Code identifizieren – Gute Tests mit 50% Abdeckung > Schlechte Tests mit 99% Abdeckung • Mythos: Unit Tests sind teuer – Nicht wenn sie sinnvoll eingesetzt werden! – Noch einmal für die Projektmanager: (L * W) / (M * K) Fabian Schmengler – Pragmatisches Unit Testing 38
Rewrites testen, um Konflikte zu erkennen • Folklore: Unit Tests mit unzähligen Mocks – Führt letztendlich zu unwartbaren und unzuverlässigen Tests • Folklore: YAML Fixtures – Zusätzliche Abstraktionsebene und Fehlerquelle – Im Zweifel Produkte etc. lieber per Code vorbereiten Fabian Schmengler – Pragmatisches Unit Testing 39
mit degenerierter Test Suite: – Phase 1: Viele Stunden mit Reparieren von Tests verbringen – Phase 2: Bekannte False Positives ignorieren – Phase 3: Alle Failures ignorieren. Keine neuen Tests mehr schreiben, weil eh nicht mehr erkennbar ist, welche Tests zu Recht fehlschlagen und welche nicht. • Broken Windows Theory • Defekte Tests lieber deaktivieren, als sie mitzuschleifen! • Test-Strategie regelmäßig hinterfragen: Tun wir (noch) das Richtige? Haben die Tests noch Wert? Fabian Schmengler – Pragmatisches Unit Testing 40
manuelles Testen genügen • Automatisierung von Smoke Tests immer sinnvoll, wenn die Infrastruktur vorhanden ist – Noch einmal: (L * W) / (M * K) • Keine Test-Automatisierung => viel Zeit für manuelles Testen einplanen • Kein manuelles Testen => viel Bugfixing im Panik- Modus einplanen Fabian Schmengler – Pragmatisches Unit Testing 42
mit Unit Tests versehen, aber großteils – Portiert von Magento 1 – Nicht testgetrieben entwickelt • Abhängigkeiten sind durch DI expliziter, aber – Immer noch viel zu instabil – Immer noch gibt es schwarze Löcher wie die Registry Fabian Schmengler – Pragmatisches Unit Testing 43
Neue Technik: Magento 2 TestFramework für Integration Tests statt EcomDev_PHPUnit oder xtest • Immerhin gibt es die Gott-Klasse „Mage“ nicht mehr Fabian Schmengler – Pragmatisches Unit Testing 45