In diesem Beitrag geht es darum, wie ich PHPUnit in der lokalen Entwicklungsumgebung und auf GitHub Actions für Willow CMS eingerichtet habe. Zum Zeitpunkt des Schreibens verfügt Willow über 116 Tests und 414 Behauptungen. Dies gibt mir ein angemessenes Maß an Vertrauen, um die Zuverlässigkeit und Qualität der Codebasis sicherzustellen. Hier sind die Schlüsselkomponenten meines Test-Setups und wie sie zu einer gut getesteten Anwendung beitragen.
1. PHPUnit-Konfiguration (phpunit.xml.dist)
Die Datei phpunit.xml.dist ist die Hauptkonfiguration von PHPUnit. Sie definiert wichtige Einstellungen wie Speichergrenzen, Fehlerberichte und die Testsuite-Struktur. Sie ist so konfiguriert, dass sie Folgendes enthält:tests/TestCase/
Verzeichnis, in dem alle meine Testfälle gespeichert sind. Außerdem wird PHPUnit so konfiguriert, dass die CakePHP-Fixture-Erweiterung verwendet wird, die die Datenbankeinrichtung für Tests vereinfacht. Sie erhalten dies kostenlos mit einer CakePHP-Installation. Eine Sache, die ich angepasst habe, ist die Randomisierung von Tests mitexecutionOrder="random"
. Die zufällige Reihenfolge der Testausführung ist eine gute Möglichkeit, um sicherzustellen, dass keine versteckten Abhängigkeiten zwischen den Tests bestehen. Wenn Tests in einer festen Reihenfolge ausgeführt werden, ist es möglich, dass ein Test versehentlich vom Zustand oder den Nebeneffekten eines anderen Tests abhängt. Dies würden Sie nie bemerken, wenn Sie die Tests bei jedem Durchlauf in derselben Reihenfolge ausführen. Gute Tests sind wirklich unabhängig und in sich geschlossen.
Eine weitere Anpassung (die jedoch in den letzten Commits entfernt wurde) ist die Aufnahme einer Bereinigungsklasse, die ich in PHP geschrieben hatte und die nach der Testausführung ausgeführt wurde. Ich hatte nach dem Ausführen von Tests Probleme mit den Berechtigungen zwischen der Docker-Entwicklungsumgebung und meinem Host-Dateisystem. Es genügt zu sagen, dass es möglich ist, diephpunit.xml.dist
Datei, um PHP-Code zu konfigurieren, den Sie an verschiedenen Punkten der PHPUnit-Ausführung ausführen möchten.
Sie können sich die Konfiguration und den Code ansehen, die ich damals dafür hatte, und mehr über PHPUnit-Erweiterungen in der PHPUnit-Dokumentation lesen. Hier ist ein Link zur Datei phpunit.xml.dist in ihrem aktuellen Zustand.
2. Kontinuierliche Integration mit GitHub Actions (.github/workflows/ci.yml)
Um meinen Testprozess zu automatisieren, habe ich einen Continuous Integration (CI)-Workflow mit GitHub Actions eingerichtet. Anfangs fand ich GitHub Actions ziemlich knifflig, da mehrere Runden erforderlich waren, um eine Konfigurationsänderung vorzunehmen, diese Änderung in das Repository zu übertragen und sie dann auf GitHub hochzuladen, um zu sehen, ob sie funktioniert. Wenn Sie GitHub Actions nicht kennen, lesen Sie hier mehr. Es ist genial und ich habe wirklich nur an der Oberfläche gekratzt.
Der.github/workflows/ci.yml
Die Datei definiert die Schritte, die auf einer virtuellen Maschine in der Cloud ausgeführt werden sollen, wenn ich Änderungen an bestimmte Zweige übertrage oder eine Pull-Anfrage erstelle. Die Schritte umfassen die Installation von Software auf der Maschine sowie die Konfiguration. Sehen Sie sich die Datei an, um zu sehen, wie ich Dinge wie die Installation und den Start von MySQL, die Installation von PHP-Abhängigkeiten mit Composer und das Kopieren von CakePHP-Konfigurationsdateien an die richtige Stelle mache.
Sie erhalten nur eine virtuelle Maschine und nur eine bestimmte Anzahl von Minuten Ausführungszeit pro Monat, daher sollte diese Phase so leicht und schnell wie möglich sein. Im Gegensatz zur Docker-Entwicklungsumgebung (zukünftiger Blogbeitrag) richte ich keine „Nice-to-haves“ wie Redis, PHPMyAdmin usw. ein – dies ist nur eine einzelne virtuelle Maschine mit den absolut notwendigen Funktionen, um das Einrichten einer MySQL-Datenbank, das Installieren von PHP-Abhängigkeiten, das Ausführen von PHPUnit-Tests und die Durchführung statischer Analysen mit Tools wie PHP CodeSniffer und PHPStan zu ermöglichen.
Das Endziel besteht darin, dass mein Code gründlich getestet wird und den Codierungsstandards entspricht, bevor er in den Hauptzweig integriert wird.
3. Gemeinsam genutzter Testfallcode (tests/TestCase/AppControllerTestCase.php)
Um meinen Testcode DRY (Don't Repeat Yourself) zu halten, habe ich eine wiederverwendbareAppControllerTestCase
Klasse, die CakePHP erweitertTestCase
. Diese Klasse stellt allgemeine Funktionen für Controllertests bereit, die im Moment nur Benutzerauthentifizierungsmethoden über dieloginUser
Methode. Schauen Sie sich die Datei an .
Obwohl ich Tests für die Anmeldemethode habe, möchte ich nicht jedes Mal, wenn ich eine Funktion im Admin-Bereich testen möchte, diese „richtige“ Anmeldung durchführen müssen (buchstäblich die Anmeldeinformationen des Testbenutzers an die Anmeldeaktion senden). Der Testcode sollte sich auf das zu testende Objekt konzentrieren und keinen Code vor oder nach dem einführen, was wir testen möchten. In diesem Fall ist dafür ein Mechanismus erforderlich, um problemlos einen Startpunkt mit einem angemeldeten Benutzer zu haben.
Schauen Sie sich einige Tests im Benutzer-Controller an, die einfach die Methode loginUser aufrufen, und gehen Sie dann direkt zum eigentlichen Test über.
4. Controller-Tests für die wichtigen Dinge (tests/TestCase/Controller/UsersControllerTest.php)
Zwei kritische zu testende Kontrollelemente sind dieUsersController
und dieArticlesController
für die Admin- und Nicht-Admin-Seite von Willow. DieUsersControllerTest
Die Klasse deckt ein breites Spektrum an Szenarien ab, darunter Anmeldung, Abmeldung, Registrierung, E-Mail-Bestätigung und Benutzerbearbeitung sowohl im Admin-Bereich als auch auf der Front-End-Site für registrierte Benutzer.
Sehen Sie sich die Dateien hier und hier an. Eine Verbesserung für die Zukunft wäre, diese in separate Testfälle für die Administrator- und Nicht-Administrator-Controller aufzuteilen. Es empfiehlt sich, sowohl erfolgreiche als auch erfolglose Szenarien zu testen, um sicherzustellen, dass sich die Anwendung korrekt verhält – testen Sie nicht nur den Happy Path. Ich überprüfe beispielsweise, ob sich sowohl ein Nicht-Administrator-Benutzer als auch ein Administrator-Benutzer anmelden können, und teste, ob einem Nicht-Administrator- Benutzer oder einem nicht angemeldeten Benutzer der Zugriff auf den Administratorbereich verweigert wird.
5. Code Coverage Bericht
Sie müssen wissen, wo Sie stehen, um besser zu verstehen, wo Sie mit dem Testen hin müssen. Um Einblicke in die Abdeckung meiner Tests zu erhalten, erstelle ich mit PHPUnit einen Code Coverage Report. Ich habe Aliase in meinemdev_aliases.txt
Datei, um PHPUnit einfach mit Abdeckungsoptionen auszuführen. Schauen Sie hier .
Derphpunit_cov
alias generiert einen textbasierten Abdeckungsbericht, der im Terminal angezeigt wird, währendphpunit_cov_html
erzeugt einen HTML-Bericht imwebroot/coverage
Verzeichnis. Diese Berichte helfen mir, Bereiche der Codebasis zu identifizieren, die keine ausreichende Testabdeckung aufweisen, und unterstützen mich beim Schreiben zusätzlicher Tests.
Durch die Implementierung dieser Testverfahren konnte ich mehrere Vorteile erzielen:
- Erhöhtes Vertrauen in die Stabilität und Zuverlässigkeit von Willow CMS
- Frühzeitige Erkennung von Fehlern und Regressionen durch automatisierte Tests – ich weiß sehr schnell, ob mein neuester Code die Kernfunktionalität beeinträchtigt hat
- Verbesserte Codequalität durch Durchsetzung von Codierungsstandards und Best Practices
- Schnellere Entwicklungszyklen durch frühzeitiges Erkennen von Problemen im Entwicklungsprozess
- Einfachere Zusammenarbeit mit (hoffentlich) anderen Entwicklern durch eine klar definierte Teststrategie
Für die Zukunft plane ich einige Verbesserungen:
- Unterteilen Sie die Testfälle in Administrator- und Nicht-Administratorfunktionen für wichtige Controller.
- Erweitern Sie die Testsuite, um mehr Randfälle und komplexe Szenarien abzudecken, wenn ich Funktionen hinzufüge
- Nutzen Sie den lokalen Jenkins Docker-Container, der Teil der Entwicklerumgebung ist, stärker, um eine Reihe automatisierter Front-End-Tests über verschiedene Browser auszuführen
Mein jetziges Ich dankt meinem früheren Ich auf jeden Fall für die Mühe, die ich mit diesen Tests gemacht habe, und ich bin sicher, dass mein zukünftiges Ich meinem jetzigen Ich dafür danken wird, dass es weiterhin daran arbeitet. Beim Testen geht es nicht nur darum, Fehler zu finden; es geht darum, Vertrauen in Ihren Code aufzubauen und schnellere, zuverlässigere Entwicklungszyklen zu ermöglichen.
Weiterführende Literatur:
Viel Spaß beim Testen!
Zusätzlich
Jetzt sind Sie auf dem Laufenden. Wie wäre es, wenn Sie weiterlesen, um eine detailliertere Aufschlüsselung der ci.yml-Datei von GitHub Actions zu erhalten?
Deep Dive – ci.yml für GitHub Actions
Die Datei ci.yml enthält alle wichtigen Funktionen zur Automatisierung des kontinuierlichen Integrationsprozesses mit GitHub Actions. Lassen Sie uns ihre Struktur und Funktionalität im Detail aufschlüsseln. Sie können sich hier einen tatsächlichen Durchlauf des Workflows ansehen.
Benennen und Auslösen von Ereignissen
Der Workflow heißtCI
, was für Continuous Integration steht. Es ist so konzipiert, dass es bei bestimmten Ereignissen automatisch ausgeführt wird:
- Push-Ereignisse: Der Workflow wird ausgelöst durch Push-Ereignisse an den
main
,development
,staging
und alle Zweige, die dem folgenfeature/*
Namenskonvention. Dadurch wird sichergestellt, dass alle in diese Zweige übertragenen Änderungen automatisch getestet werden. - Pull Request Events: Es löst auch Pull Requests aus, die auf die
main
,development
, Undstaging
Zweige. Dies hilft bei der Validierung der Änderungen, bevor sie in diese kritischen Zweige integriert werden.
name: CI
on:
push:
branches:
- main
- development
- staging
- 'feature/*'
pull_request:
branches:
- main
- development
- staging
Jobs und Umwelt
Der Workflow definiert einen einzelnen Job namenstest
, das auf demubuntu-latest
Umgebung. Dadurch wird sichergestellt, dass die Tests in einer konsistenten und aktuellen Linux-Umgebung ausgeführt werden.
jobs:
test:
runs-on: ubuntu-latest
Matrix-Strategie
Ich habe eine Strategiematrix gewählt, um die Anwendung über mehrere PHP-Versionen hinweg zu testen (8.1
,8.2
,8.3
). Das bedeutet nur, dass die folgenden Schritte für jede PHP-Version ausgeführt werden und dies für uns über GitHub Actions abgewickelt wird. Wir könnten dem Array bei Bedarf PHP 8.4 hinzufügen.
strategy:
matrix:
php-version: ['8.1', '8.2', '8.3']
Checkout-Code:
Deractions/checkout@v4
Die Aktion wird verwendet, um den Repository-Code in die Runner-Umgebung zu klonen. Dies ist normalerweise der erste Schritt in jedem CI-Prozess, da er die zu bearbeitende Codebasis bereitstellt.
steps:
- uses: actions/checkout@v4
MySQL einrichten:
Der MySQL-Dienst wird gestartet und eine Testdatenbankcms_test
wird erstellt. Beachten Sie, dass wir kein SQL laden, um Datenbanktabellen zu erstellen - das wird von CakePHP erledigt, das die Migrationen ausführt, wenn wir die Tests ausführen, da die Datei phpunit.xml.dist die testspezifische Bootstrap-Datei angibt, um die Dinge mit der Zeile zu startenbootstrap="tests/bootstrap.php"
- name: Setup MySQL
run: |
sudo service mysql start
mysql -e 'CREATE DATABASE IF NOT EXISTS cms_test;' -uroot -proot
mysql -e 'SHOW DATABASES;' -uroot -proot
PHP einrichten:
Dershivammathur/setup-php@v2
Mit dieser Aktion können Sie die angegebenen PHP-Versionen aus der Matrix einzeln einrichten . Außerdem werden erforderliche PHP-Erweiterungen installiert, wiembstring
,intl
,pdo_mysql
usw. und ermöglicht Code-Coverage mitxdebug
.
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
extensions: mbstring, intl, pdo_mysql, pcntl, sockets, bcmath, zip
coverage: xdebug
Installieren Sie Composer-Abhängigkeiten:
Composer ist so konfiguriert, dass die PHP-Version aus der Matrix verwendet wird, und Abhängigkeiten sind installiert .--no-interaction
,--prefer-dist
, Und--ignore-platform-reqs
Flags sorgen für einen reibungslosen und nicht interaktiven Installationsprozess. Dies ist der Schritt, der das CakePHP-Framework und andere von Willow CMS verwendete Dinge im Ordner /vendors installiert.
- name: Install Composer dependencies
run: |
composer config platform.php ${{ matrix.php-version }}
composer update --no-interaction --prefer-dist --ignore-platform-reqs
Konfigurationen kopieren:
Konfigurationsdateien werden aus einem angegebenen Verzeichnis in das Konfigurationsverzeichnis der Anwendung kopiert. Dieser Schritt stellt sicher, dass die Anwendung während der Tests die richtigen umgebungsspezifischen Konfigurationen verwendet. Da die Docker-Entwicklungsumgebung mehrere Container für verschiedene Dienste hat und GitHub Actions dem Job eine einzelne VM zuweist, gibt es wichtige Konfigurationsunterschiede wie die MySQL-Serveradresse. Wir könnten hierfür mehr mit Umgebungsvariablen tun, aber im Moment ist dies einfach und funktioniert.
- name: Copy Configs
run: |
cp docker/github/cms_app_local_github.php config/app_local.php
cp docker/github/app_github.php config/app.php
Debuggen Sie app_local.php:
Der Inhalt vonapp_local.php
werden angezeigt. Dies ist nützlich zum Debuggen und Überprüfen, ob die richtige Konfiguration verwendet wird, falls etwas schief geht.
- name: Debug app_local.php
run: cat "config/app_local.php"
Führen Sie PHPUnit aus:
PHPUnit-Tests werden mit aktivierter Fehleranzeige ausgeführt .XDEBUG_MODE: coverage
Die Umgebungsvariable ist so eingestellt, dass sie Codeabdeckungsdaten sammelt, sodass Sie die Abdeckungsstatistiken in der Ausgabe lesen können. Ich denke, in Zukunft werde ich dies möglicherweise deaktivieren, da sie in der Praxis auf GitHub nicht sehr einfach zu lesen sind.
- name: Run PHPUnit
run: php -d display_errors=on -d error_reporting=E_ALL vendor/bin/phpunit
env:
XDEBUG_MODE: coverage
Führen Sie PHP CodeSniffer aus:
PHP CodeSniffer wird ausgeführt, um sicherzustellen, dass der Code den CakePHP-Codierungsstandards entspricht. Dies trägt dazu bei, die Qualität und Konsistenz des Codes aufrechtzuerhalten. Es erkennt Leerzeichenfehler, Yoda-Vergleiche, PHP-Use-Anweisungen, die nicht in alphabetischer Reihenfolge stehen, nicht verwendete Variablen und mehr. Beachten Sie, dass ich dies nur in den Ordnern „src“ und „tests“ ausführe, da diese den reinen PHP-Code enthalten und Ordner wie Vorlagen eine Mischung aus PHP und HTML sind.
- name: Run PHP CodeSniffer
run: vendor/bin/phpcs --standard=vendor/cakephp/cakephp-codesniffer/CakePHP src/ tests/
Führen Sie PHPStan aus:
PHPStan wird zur statischen Analyse des Codes verwendet. Es prüft auf mögliche Fehler und Probleme mit der Codequalität.continue-on-error: true
Mit dieser Option kann der Workflow fortgesetzt werden, auch wenn PHPStan Probleme findet. Dies kann für nicht blockierendes Feedback nützlich sein. Sie werden sehen, dass ich den Job so konfiguriert habe, dass er bei diesem Schritt bei einem Fehler fortgesetzt wird, da es im Moment ausreicht, sich auf das Schreiben von Tests zu konzentrieren und die CakePHP-Codierungsstandards einzuhalten.
- name: Run PHPStan
run: php -d memory_limit=-1 vendor/bin/phpstan analyse src/
continue-on-error: true