
Automatisierte Tests mit Codeception: So sichern wir Webprojekte ab
Codeception hilft uns dabei, zentrale Funktionen einer Website nach Updates, Relaunches oder Deployments automatisiert zu testen.
Nach einem Update, Relaunch oder Deployment stellt sich oft dieselbe Frage: Funktioniert noch alles? Lässt sich das Kontaktformular absenden? Öffnet sich der Login? Erscheint der Cookie-Banner? Genau an dieser Stelle helfen automatisierte Tests. Sie prüfen wiederkehrende Abläufe nicht manuell, sondern reproduzierbar und zuverlässig. In vielen unserer Projekte setzen wir dafür Codeception ein – vor allem für automatisierte Browser-Tests.
In diesem Beitrag zeigen wir dir, welche Testarten es gibt, warum Akzeptanztests für Webprojekte besonders wertvoll sind, wie Codeception funktioniert und welche Erfahrungen wir bei clickstorm damit gemacht haben.
Welche Testarten gibt es?
Automatisierte Tests können auf unterschiedlichen Ebenen ansetzen. Jede Testart verfolgt ein anderes Ziel und hat ihre eigene Berechtigung. TYPO3 unterscheidet in der offiziellen Dokumentation ebenfalls zwischen verschiedenen Testebenen wie Unit-, Functional- und Acceptance-Tests.
Unit-Tests
Unit-Tests prüfen einzelne, möglichst kleine Code-Einheiten isoliert. Das können Funktionen, Methoden oder Klassen sein. Sie sind schnell, gut automatisierbar und eignen sich besonders für Logik, Berechnungen oder klar abgegrenzte Geschäftsregeln.
Ein Unit-Test beantwortet zum Beispiel die Frage:
Liefert diese Methode bei einer bestimmten Eingabe das erwartete Ergebnis?
Gerade in TYPO3-, Symfony- oder Shopware-Projekten sind Unit-Tests hilfreich, wenn individuelle Logik sauber abgesichert werden soll.
Funktionale Tests
Funktionale Tests prüfen bestimmte Funktionen innerhalb einer Anwendung. Sie liegen häufig zwischen Unit-Tests und Akzeptanztests. Im TYPO3-Umfeld werden funktionale Tests zum Beispiel genutzt, um Verhalten mit einer realistischeren TYPO3-Umgebung zu testen.
Typische Fragen sind:
Wird ein Datensatz korrekt verarbeitet?
Wird eine bestimmte Funktion innerhalb der Anwendung wie erwartet ausgeführt?
Funktioniert ein Plugin oder eine Extension mit der vorhandenen Konfiguration?
Akzeptanztests
Akzeptanztests prüfen komplette Abläufe aus Sicht der Nutzerinnen und Nutzer. Sie simulieren typische Wege durch eine Website oder Webanwendung: Seite öffnen, Button klicken, Formular ausfüllen, absenden und Ergebnis prüfen.
TYPO3 beschreibt Acceptance Testing als das Steuern eines Browsers, um durch ein Frontend oder Backend-Szenario zu klicken. Genau in diesem Bereich setzen wir Codeception in vielen Projekten ein.
Warum Akzeptanztests besonders wertvoll sind
Akzeptanztests sind besonders nah an der tatsächlichen Nutzung einer Website. Sie prüfen nicht nur, ob einzelne Code-Bausteine funktionieren, sondern ob ein kompletter Ablauf erfolgreich ist.
Ein Beispiel: Ein Kontaktformular besteht aus vielen einzelnen Teilen. Es gibt ein Template, Formularfelder, Validierung, Spam-Schutz, Versandlogik, Weiterleitungen und Erfolgsmeldungen. Ein Akzeptanztest prüft nicht jedes Detail isoliert, sondern den gesamten Weg:
- Kontaktseite öffnen
- Formularfelder ausfüllen
- Formular absenden
- Erfolgsmeldung prüfen
Das ist besonders wertvoll bei wiederkehrenden manuellen Tests. Vor einem Deployment muss nicht jedes Formular, jeder Login oder jeder Anfrageprozess per Hand durchgeklickt werden. Stattdessen übernehmen automatisierte Tests diese Aufgabe.
Natürlich ersetzen solche Tests keine gute Entwicklung, kein Code-Review und keine fachliche Abnahme. Aber sie schaffen zusätzliche Sicherheit und helfen, Fehler frühzeitig zu erkennen.
Was ist Codeception?
Codeception ist ein Testing-Framework für PHP. Es unterstützt verschiedene Testarten und legt einen starken Fokus auf lesbare, nutzernahe Tests. Die offizielle Codeception-Seite beschreibt das Framework als Lösung für das Testen von PHP-Webanwendungen mit Modulen für unter anderem Browser-Testing und nutzerzentrierte Tests.
Für Browser-Tests kann Codeception das WebDriver-Modul nutzen. Damit laufen Tests in echten Browsern über das W3C-WebDriver-Protokoll, zum Beispiel mit Chrome oder Firefox.
Für uns ist besonders wichtig: Die Tests werden in PHP geschrieben. Als Agentur mit Schwerpunkten in TYPO3, WordPress, Shopware, Symfony und individuellen PHP-Projekten passt das sehr gut zu unserem Alltag. Wir bleiben in einer Sprache und einem Ökosystem, das unser Team ohnehin täglich nutzt.
Wie funktionieren Browser-Tests mit Codeception?
Ein Browser-Test mit Codeception beschreibt einen Ablauf so, wie ihn auch ein Mensch im Browser durchführen würde.
Zum Beispiel:
$I->amOnPage('/kontakt');
$I->fillField('Name', 'Max Mustermann');
$I->fillField('E-Mail', 'max@example.de');
$I->fillField('Nachricht', 'Das ist eine Testnachricht.');
$I->click('Absenden');
$I->see('Vielen Dank');Der Test liest sich fast wie eine kleine Anleitung:
- Gehe auf die Kontaktseite.
- Fülle die Felder aus.
- Klicke auf Absenden.
- Prüfe, ob die Erfolgsmeldung erscheint.
Das macht Codeception auch für Teams gut verständlich, die nicht jeden Tag komplexe Testframeworks konfigurieren möchten.
Codeception installieren
Codeception kann in einem PHP-Projekt über Composer installiert werden. Für Browser-Tests werden neben Codeception selbst auch passende Module benötigt.
composer require codeception/codeception \ codeception/module-asserts \ codeception/module-phpbrowser \ codeception/module-webdriver \ --dev
Anschließend wird Codeception initialisiert:
vendor/bin/codecept bootstrap
Dabei erzeugt Codeception die grundlegende Konfiguration und die Teststruktur im Projekt.
Falls Autoloading für Tests oder projektspezifische Namespaces benötigt wird, kann die composer.json entsprechend erweitert werden:
{
"autoload-dev": {
"psr-4": {
"Tests\\": "tests"
}
}
}Danach sollte der Autoloader neu erzeugt werden:
composer dump-autoload -o
Selenium starten
Für echte Browser-Tests benötigt Codeception einen WebDriver. Häufig wird dafür Selenium genutzt.
Eine lokale Möglichkeit ist selenium-standalone über npm:
npm install selenium-standalone -g selenium-standalone install selenium-standalone start
Wenn der ChromeDriver nicht mehr zur installierten Chrome-Version passt, kann er aktualisiert werden:
selenium-standalone install --drivers.chrome.version=latest
Das ist eine typische Fehlerquelle in der Praxis. Wenn Tests plötzlich keine Verbindung mehr zum Browser herstellen können oder Chrome nicht korrekt startet, lohnt sich oft zuerst ein Blick auf die Versionen von Chrome und ChromeDriver.
Codeception mit DDEV und Selenium nutzen
In DDEV-Projekten bietet sich das Add-on ddev-selenium-standalone-chrome an. Es stellt Selenium mit Chrome als Service innerhalb der DDEV-Umgebung bereit. Das Add-on ist laut Projektbeschreibung für browserbasierte Tests mit Selenium in DDEV gedacht und kann grundsätzlich mit verschiedenen Projekttypen genutzt werden.
Die Installation erfolgt zum Beispiel mit:
ddev add-on get ddev/ddev-selenium-standalone-chrome ddev restart
Anschließend muss Codeception so konfiguriert werden, dass es den Selenium-Service innerhalb von DDEV nutzt.
Ein Beispiel für eine codeception.yml oder eine Suite-Konfiguration:
actor: AcceptanceTester
modules:
enabled:
- WebDriver:
url: https://myproject.ddev.site
host: selenium-chrome
browser: chrome
capabilities:
goog:chromeOptions:
args:
- '--ignore-certificate-errors'
- '--disable-dev-shm-usage'Die beiden Chrome-Argumente sind in DDEV-Projekten besonders praktisch:
--ignore-certificate-errors
Damit akzeptiert Chrome selbstsignierte DDEV-Zertifikate.
--disable-dev-shm-usage
Das kann Probleme mit gemeinsam genutztem Speicher in Container-Umgebungen vermeiden.
Lokale Projekt-URLs sollten nicht fest in Git landen. Deshalb kann die URL auch über eine Umgebungsvariable gesetzt werden, zum Beispiel:
url: '%CODECEPTION_URL%'
Beispiel: Ein Formular automatisch testen
Ein typischer Akzeptanztest prüft, ob ein Formular erreichbar ist, sich ausfüllen lässt und nach dem Absenden die erwartete Rückmeldung erscheint.
<?php
class ContactFormCest
{
public static string $URL_CONTACT = '/kontakt';
public static string $CSS_SUCCESS_MESSAGE = '.success-message';
public function contactFormCanBeSubmitted(AcceptanceTester $I): void
{
$I->wantTo('submit the contact form');
$I->amOnPage(static::$URL_CONTACT);
$I->see('Kontakt');
$I->fillField('Name', 'Max Mustermann');
$I->fillField('E-Mail', 'max@example.de');
$I->fillField('Nachricht', 'Das ist eine Testnachricht.');
$I->click('Absenden');
$I->waitForElementVisible(static::$CSS_SUCCESS_MESSAGE, 10);
$I->see('Vielen Dank');
}
}Dieser Test ist bewusst einfach gehalten. In echten Projekten kommen häufig weitere Aspekte hinzu: Pflichtfelder, Validierungsfehler, Spam-Schutz, Weiterleitungen, mehrsprachige Formulare oder unterschiedliche Formularvarianten.
Codeception-Tests ausführen
Codeception-Tests können direkt über die Konsole gestartet werden:
vendor/bin/codecept run --steps --html
Mit --steps werden die einzelnen Schritte ausgegeben. Mit --html wird ein HTML-Report erzeugt. Das ist besonders hilfreich, wenn Tests in CI/CD-Prozessen laufen oder wenn ein Fehler später nachvollzogen werden soll.
Ein einzelner Test kann so gestartet werden:
vendor/bin/codecept run tests/Acceptance/ContactFormCest.php --steps --html
Nur fehlgeschlagene Tests können erneut ausgeführt werden:
vendor/bin/codecept run --steps --html --group failed
Wenn veraltete Testreferenzen Probleme machen, hilft manchmal ein Clean-Lauf:
vendor/bin/codecept clean
Codeception in PhpStorm starten
Codeception-Tests lassen sich nicht nur über die Konsole ausführen, sondern auch direkt in PhpStorm. Das ist besonders praktisch, wenn du einzelne Tests während der Entwicklung schnell starten möchtest.
Damit PhpStorm Codeception korrekt ausführen kann, muss zuerst der passende PHP-Interpreter eingerichtet sein.

Auch der Selenium-Server muss gestartet sein (siehe oben). Anschließend sind folgende Schritte auszuführen:
- Rechtsklick auf den Test-Ordner
- „Run“ wählen
- Klick auf Codeception.

Jetzt sollte sich der Chrome-Browser öffnen. Unterhalb in PhpStorm öffnet sich ebenfalls die Run-Ansicht, wo der Fortschritt der Tests sowie fehlgeschlagene Tests zu sehen sind. Im Anschluss lassen sich auch nur die fehlgeschlagenen wiederholen.

Best Practices aus unserer Praxis
Mit der Zeit haben sich bei uns einige Regeln bewährt, die Codeception-Tests stabiler und wartbarer machen.
Selektoren bewusst definieren
Selektoren, URLs und erwartete Werte sollten nicht überall im Test verstreut stehen. Wir legen sie lieber als Variablen an. So bleiben Tests lesbarer und Änderungen lassen sich schneller durchführen.
public static string $URL_TO_TEST = '/'; public static string $CSS_LINK_DETAIL = '.test-link-detail'; public static string $CODE_IN_DETAIL_VIEW = '<h2>'; public static int $NUMBER_OF_LIST_ITEMS = 6;
Als Namenskonvention nutzen wir sprechende Präfixe:
CSS_ für CSS-Selektoren URL_ für URLs CODE_ für erwarteten HTML-Code NUMBER_OF_ für erwartete Anzahlen
Wenn CSS-Klassen nur für Tests eingeführt werden, bietet sich ein eindeutiges Präfix an, zum Beispiel:
.test-link-detail
So ist sofort sichtbar, dass diese Klasse nicht für Styling oder JavaScript gedacht ist, sondern für automatisierte Tests.
Robuste XPath-Selektoren verwenden
Manchmal reicht ein einfacher CSS-Selektor nicht aus. Wenn ein Element anhand einer Klasse und eines konkreten Textes gefunden werden soll, kann XPath helfen:
public static $XPATH_ITEM = '//li[contains(concat(" ", normalize-space(@class), " "), " mycssclass ")][text()="mytext"]';Solche Selektoren sollten sparsam eingesetzt werden, können aber bei komplexeren Templates hilfreich sein.
Nicht fest warten, sondern gezielt warten
Eine der wichtigsten Regeln: Tests sollten möglichst nicht einfach eine feste Anzahl Sekunden warten.
Stattdessen ist es besser, auf einen konkreten Zustand zu warten:
$I->waitForElementVisible(static::$CSS_AJAX_IS_LOADING, $timeout); $I->waitForElementNotVisible(static::$CSS_AJAX_IS_LOADING, $timeout);
Oder darauf, dass das Dokument fertig geladen ist:
$I->waitForJS('return document.readyState == "complete"');Codeception unterstützt verschiedene Wait-Methoden im WebDriver-Modul; außerdem beschreibt die Dokumentation mit „SmartWait“ einen Mechanismus, bei dem Codeception beim Suchen bestimmter Elemente kurz warten kann, ohne alle Testschritte pauschal auszubremsen.
In der Praxis ist das wichtig, weil viele Websites heute mit Ajax, Animationen, Consent-Bannern oder nachgeladenen Inhalten arbeiten. Ein Test, der zu früh klickt oder prüft, kann fehlschlagen, obwohl die Website korrekt funktioniert.
Optionale Elemente mit tryTo prüfen
Nicht jedes Element ist immer sichtbar. Ein Sprachmenü kann temporär ausgeblendet sein. Ein Veranstaltungskalender kann leer sein. Ein Hinweis kann nur unter bestimmten Bedingungen erscheinen.
Für solche Fälle können tryTo-Methoden hilfreich sein. Dafür werden Step Decorators in der Konfiguration aktiviert:
suites:
acceptance:
actor: AcceptanceTester
step_decorators:
- \Codeception\Step\TryTo
- \Codeception\Step\ConditionalAssertionDanach muss Codeception neu gebaut werden:
vendor/bin/codecept build
Anschließend können optionale Elemente abgefragt werden, ohne dass der Test sofort abbricht:
public function checkLanguageMenu(AcceptanceTester $I): void
{
if ($I->tryToSeeElement(static::$CSS_LANG_MENU)) {
$I->wantTo('click the language selector');
$I->click(static::$CSS_LANG_MENU);
$I->seeInCurrentUrl(static::$URL_EN);
}
}Das sollte gezielt eingesetzt werden. Nicht jeder Fehler sollte „weich“ abgefangen werden. Wenn ein Element zwingend vorhanden sein muss, sollte der Test auch klar fehlschlagen.
Testmodus per CSS-Klasse markieren
Manchmal verhalten sich Websites im Testkontext anders als gewünscht. Ein Beispiel ist scroll-behavior: smooth, das bei automatisierten Scroll-Methoden Probleme verursachen kann.
In solchen Fällen kann eine Klasse am HTML-Element helfen:
$I->executeJS("document.documentElement.classList.add('test-runner');");Im CSS oder Less kann dann gezielt reagiert werden:
.test-runner {
scroll-behavior: auto;
}Wichtig ist: Solche Anpassungen sollten den Test stabiler machen, aber keine echten Fehler verstecken.
Mehrere Varianten mit @example testen
Wenn derselbe Ablauf mit unterschiedlichen Daten getestet werden soll, können Beispiele direkt am Test hinterlegt werden.
/**
* @example { "startDate": "1.1.2010", "endDate": "1.1.2020", "expectedDate": "01.01.2010", "expectedNumber": "27 Suchergebnisse" }
* @example { "startDate": "1.1.2020", "endDate": "1.1.2024", "expectedDate": "01.01.2024", "expectedNumber": "12 Suchergebnisse" }
*/
public function filterAndOpenDetails(AcceptanceTester $I, \Codeception\Example $example): void
{
$I->wantTo('filter and open details');
$I->fillField(static::$CSS_FILTER_DATE_FROM, $example['startDate']);
$I->fillField(static::$CSS_FILTER_DATE_TO, $example['endDate']);
$I->see($example['expectedDate']);
$I->see($example['expectedNumber']);
}Das ist praktisch für Filter, Suchfunktionen, Datumsbereiche oder Formularvarianten.
Sensible Daten in der .env-Datei speichern
Zugangsdaten gehören nicht ins Git-Repository. Für Testlogins nutzen wir Umgebungsvariablen, zum Beispiel:
TEST_EXTENSIONS_CSFEUSER_USER='username' TEST_EXTENSIONS_CSFEUSER_PASS='password'
Im Test können diese Werte ausgelesen werden:
$I->fillField('Benutzername', getenv('TEST_EXTENSIONS_CSFEUSER_USER'));
$I->fillField('Passwort', getenv('TEST_EXTENSIONS_CSFEUSER_PASS'));So bleiben Tests automatisierbar, ohne sensible Daten im Code abzulegen.
Hilfsmethoden nicht public machen
Gut zu wissen: Öffentliche Methoden in einer Cest-Klasse werden von Codeception als Tests erkannt.
Wenn du Hilfsmethoden schreiben möchtest, solltest du sie deshalb protected oder private machen:
protected function login(AcceptanceTester $I): void
{
$I->amOnPage('/login');
$I->fillField('Benutzername', getenv('TEST_USER'));
$I->fillField('Passwort', getenv('TEST_PASS'));
$I->click('Einloggen');
}Das hält Tests sauber und verhindert, dass Hilfslogik versehentlich als eigener Testlauf ausgeführt wird.
Video: Codeception in der Praxis
Wenn du Codeception lieber in Aktion sehen möchtest, findest du in diesem Video einen guten Einstieg in automatisierte Tests mit PHP und Selenium:
Dieses Video wird über eine externe Plattform (YouTube) gehostet. Das Laden bedarf der Zustimmung unserer Datenschutzbestimmungen.
Unsere Erfahrungen mit Codeception
Wir nutzen Codeception in vielen Projekten, weil es gut zu unserem PHP-Stack passt. Gerade für TYPO3-, WordPress-, Symfony- und Shopware-Projekte ist es angenehm, Browser-Tests in PHP schreiben zu können.
Unsere wichtigsten Erfahrungen:
Codeception ist gut lesbar.
Tests beschreiben Nutzerwege verständlich: Seite öffnen, Feld ausfüllen, Button klicken, Ergebnis prüfen.
PHP ist für uns ein Vorteil.
Wir müssen für viele Tests nicht in ein separates JavaScript- oder TypeScript-Setup wechseln. Das erleichtert Einstieg, Wartung und Verständnis im Team.
Browser-Tests brauchen Pflege.
Tests sind keine einmalige Aufgabe. Wenn sich Templates, Selektoren oder Abläufe ändern, müssen auch Tests angepasst werden.
Wartezeiten sind eine typische Fehlerquelle.
Viele scheinbar instabile Tests entstehen nicht durch echte Fehler, sondern durch Timing-Probleme. Mit gezielten Methoden wie waitForElementVisible, waitForElementNotVisible oder waitForJS lässt sich das meist gut lösen.
ChromeDriver muss gelegentlich aktualisiert werden.
Wenn Chrome und ChromeDriver nicht mehr zusammenpassen, schlagen Tests unter Umständen fehl. Mit selenium-standalone install --drivers.chrome.version=latest lässt sich das häufig schnell beheben.
Reports und Screenshots helfen beim Debugging.
HTML-Reports, Logs und Screenshots machen Fehler besser nachvollziehbar – besonders dann, wenn Tests nicht lokal, sondern automatisiert laufen.
Was automatisierte Tests leisten – und was nicht
Automatisierte Browser-Tests sind sehr hilfreich, aber sie sind kein Allheilmittel.
Sie können prüfen, ob ein definierter Ablauf funktioniert. Sie können aber nicht automatisch beurteilen, ob ein Design gut wirkt, ob eine Formulierung verständlich ist oder ob ein neues Feature fachlich sinnvoll umgesetzt wurde. Ähnlich ist es bei Barrierefreiheit: Automatisierte Checks helfen, ersetzen aber keine manuelle Prüfung. Mehr dazu liest du in unserem Beitrag „Barrierefreiheit: Warum manuelles Testen unverzichtbar bleibt“.
Deshalb sehen wir automatisierte Tests als Ergänzung zu sauberer Entwicklung, manueller Prüfung, Code-Reviews und fachlicher Abnahme.
Besonders stark sind sie bei wiederkehrenden, kritischen Abläufen:
- Kontaktformulare
- Login- und Logout-Prozesse
- geschützte Bereiche
- Such- und Filterfunktionen
- Warenkorb- und Checkout-Prozesse
- Cookie-Banner und Consent-Flows
- zentrale Navigationswege
- mehrsprachige Funktionen
Fazit: Automatisierte Tests schaffen Vertrauen
Automatisierte Tests sind eine Investition in Qualität und Sicherheit. Mit Codeception können wir wichtige Nutzerwege im Browser prüfen und wiederkehrende Abläufe zuverlässig absichern. Gerade bei Relaunches, Updates und Deployments hilft das enorm: Statt zentrale Funktionen jedes Mal manuell durchzuklicken, können Tests viele dieser Prüfungen reproduzierbar übernehmen.
Für uns ist Codeception deshalb aktuell ein sehr wertvolles Werkzeug – nicht, weil es jeden Testfall löst, sondern weil es gut zu unseren Projekten, unserem PHP-Stack und unserer Arbeitsweise passt.
Neben funktionalen Abläufen spielt auch die visuelle Qualität einer Website eine wichtige Rolle. Wenn du wissen möchtest, wie sich Layout-Veränderungen automatisch erkennen lassen, lies auch unseren Beitrag zu BackstopJS und visuellen Regressionstests.
In einem kommenden Artikel schauen wir uns außerdem Playwright an – ein modernes Tool für browserbasierte End-to-End-Tests, das besonders bei Debugging, Parallelisierung und aktuellen Frontend-Setups spannend ist.
Hast du bereits Erfahrungen mit Codeception oder nutzt du andere Tools, um deine Webprojekte stabiler zu machen? Teile dein Wissen gerne in den Kommentaren.