Ein Codeception Tutorial Best Practice Pageobject mit dem Ziel zuverlässige Acceptance Tests zu erstellen. Dabei liegt der Fokus auf der Nutzung eines Pageobjects und data-Attributen für Selektoren. So werden Tests stabil und können zentral und effizient gewartet werden. Die eigentliche Entwicklungsarbeit wird dadurch auch gekapselt und sehr übersichtlich. Tests sind natürlich auch Software, die genauso entwickelt und gewartet werden muß.
Das Szenario – Marketing Features mit dem Multislider – Codeception Tutorial
Auf der Startseite von Never Code Alone ist ein Multislider Objekt. Hier werden die wichtigsten USPs unserer Employer Branding Arbeit bei den #NCAEvents abgebildet. Bei der Kommunikation mit guten HR-Teams von guten IT-Arbeitgebern verweise auf diese Stelle. Das ist ein echt cooles Element, weil hier sehr gute Referenzen und Beispiele abgebildet werden können. Gerade bei Telefonaten ist das wirklich ganz entscheidend für einen erfolgreichen Abschluss.
Von Anfang an ein Pageobject erstellen und da alle Selektoren mit sprechenden Variablennamen einpflegen – Codeception Tutorial Best Pratice
Bei der Entwicklung mit PHP ist für mich Dependency Injection absolut elementar für Arbeit. Darauf basiert in Codeception die Arbeit mit dem Pageobject. Mit dem folgenden CLI Command wird eins erstellt. vendor/bin/codecept g:pageobject Page Danach überlege ich mir gute Variablennamen, die mit einem Präfix für die PhpStorm Autovervollständigung kategorisiert werden. In diesem Falle $startpageMultisilder. Das lässt mich nachher bei den Tests sehr schönen und übersichtlichen Code schreiben. Das macht auch echt viel Spaß und der kommt ja manchmal bei der Arbeit auch zu kurz. Hier sind die Variablen und Selektoren für den Multislider
vendor/bin/codecept g:pageobject Page
Danach überlege ich mir gute Variablennamen, die mit einem Präfix für die PhpStorm Autovervollständigung kategorisiert werden. In diesem Falle $startpageMultisilder. Das lässt mich nachher bei den Tests sehr schönen und übersichtlichen Code schreiben. Das macht auch echt viel Spaß und der kommt ja manchmal bei der Arbeit auch zu kurz. Hier sind die Variablen und Selektoren für den Multislider der als Element den Namen „service“ trägt. Es ist praktisch der Service, den wir für Employer Branding Events bieten.
public static $serviceSection = '//*[@data-q="services-section"]';
public static $servicesNavigation = '//*[@data-q="services-navigation"]/li/div/a';
public static $servicesItems = '//*[@data-q="services-content"]/div';
Der Vorteil von ausgelagerten Selectoren in einem Pageobject – Codeception Tutorial HowTo
Sobald man anfängt mit Tests zu arbeiten hat man direkt viele Stellen, die man gleich verbessern möchte. Das ist auch gut so, aber nicht immer direkt möglich. Das ist aber nicht immer möglich und sollte auch alles im Team und gerade mit den Kollegen vom Frontend abgestimmt werden. Schlechte Selektoren bedeuten brüchige Tests und die will keiner haben. Ein schlechter Selector ist entweder nicht eindeutig oder beinhaltet zu viel HTML Struktur. Das erkennt man aber schon. Einige Beispiele Listen
Selector | Recommended | Notes |
---|---|---|
cy.get('button').click() |
Never | Worst – too generic, no context. |
cy.get('.btn.btn-large').click() |
Never | Bad. Coupled to styling. Highly subject to change. |
cy.get('#main').click() |
Sparingly | Better. But still coupled to styling or JS event listeners. |
cy.get('[name=submission]').click() |
Sparingly | Coupled to the name attribute which has HTML semantics. |
cy.contains('Submit').click() |
Depends | Much better. But still coupled to text content that may change. |
cy.get('[data-cy=submit]').click() |
Always | Best. Insulated from all changes. |
Codeception Tutorial Acceptance Tests Multislider
Basis für fast alle Frontend Testing Frameworks ist ein Selenium Server. Mit dem können User Interaktionen Simuliert werden. Das Codeception Framework bildet hier gemeinsam mit der Facebook Webdriver Library einen Wrapper. Im täglichen Gebrauch wird hier gescrollt, geklickt und gewartet. In der Regel holt man sich dann noch mit den Grab-Methoden bestimmte Werte und führt hier mit Hilfe von Assertions konkrete Überprüfungen durch. Das ist besonders bei Formularen sehr hilfreich. Hier schon mal der Testcode.
Vielleicht kann man den ja direkt schon lesen. Der Multislider – ein Element das alle CMS Systeme verzweifeln lässt, ist auf dieser Seite statisch eingepflegt. Tests sind aber immer noch wichtig, weil JS-Error oder das falsche Einpflegen von internen Selektoren das wichtige Marketing Modul außer Kraft setzen können. Default ist das erste Element sichtbar und alle anderen nicht sichtbar. Klickt man dann auf das zweite Element ist hier der entsprechende Container sichtbar und alle anderen nicht. Ziel des Tests ist es alle Elemente dynamisch zu überprüfen. So können Anpassungen vorgenommen werden und der Test hat möglichst wenig Abhängigkeiten.
Die Überprüfungen im einzelnen
Das erste Element ist sichtbar und alle anderen nicht: onlyFirstContentElementIsVisibleOnStart
public function onlyFirstContentElementIsVisibleOnStart(AcceptanceTester $I, startpage $startpage)
{
$contentItems = $I->grabMultiple($startpage::$servicesItems, 'id');
$first = true;
foreach ($contentItems as $contentItem) {
// First item is visible
if($first) {
$I->seeElement('#' . $contentItem);
$first = false;
continue;
}
$I->cantSeeElement('#' . $contentItem);
}
}
Tests sind Software. Die muß auch lesbar sein und auch gewartet werden. Es ist nicht so als ob man einmal einen Test schreibt und der einfach ewig gilt. Das trifft eher auch PHPUnit Tests zu. Ein Frontend hingegen ist dynamisch und hat vor allem auch immer neue Anforderungen, wenn man mit einem frischen Browser und User auf die Seite kommt. Allein der Cookie Hinweis ist hier einfach oft im Weg.
Eine der wichtigesten und besten Methoden der PHP Testing Frameworks Codeception ist grabMultiple. Als erster Paremeter gibt es den Selector und dann das Attribute. So kann man CSS-Klassen, Targets oder auch Hrefs einfach auslesen. In unserem Falle brauchen wir die IDs der Service Items. Die schreiben wir dann auf das Array $contentItems. Wir wollen schauen, ob das erste Element sichtbar ist und alle anderen nicht. Über die Bool Variable $first schauen wir dann einfach, ob das Element sichtbar ist oder nicht. Die see-Methoden werten die aktuellen CSS Eigenschaften aus. Hier können wir also einfach seeElement und cantSeeElement nutzen.
Elemente werden durchgeklickt und Edge Cases abgedeckt mit:
onClickElementIsVisibleAndAllOthersNot
public function onClickElementIsVisibleAndAllOthersNot(AcceptanceTester $I, startpage $startpage)
{
$I->scrollTo($startpage::$serviceSection);
$anchors = $I->grabMultiple($startpage::$servicesNavigation, 'href');
$contentItems = $I->grabMultiple($startpage::$servicesItems, 'id');
array_shift($anchors);
$firstItem = array_shift($contentItems);
$I->seeElement('#' . $firstItem);
foreach ($anchors as $key => $anchor)
{
$I->click('//*[@data-q="services-navigation"]/li[' . ($key + 2) . ']/div/a');
$I->waitForElementVisible('#' . $contentItems[$key]);
$actualContentItems = $I->grabMultiple($startpage::$servicesItems, 'id');
foreach ($actualContentItems as $actualContentItem) {
if($actualContentItem === $contentItems[$key]) {
continue;
}
$I->cantSeeElement('#' . $actualContentItem);
}
}
$I->scrollTo($startpage::$serviceSection);
$I->click('//*[@data-q="services-navigation"]/li[1]/div/a');
$I->waitForElementVisible('#' . $firstItem);
}
Hier wird ein recht komplexer Test ausgeführt, der zudem dynamisch und recht stabil ist. Dafür ist er mit gerade mal 30 Zeilen wirklich erstaunlich schmal. Um tatsächliche Frontend Tests mit einem simulierten Browser und User durchführen zu können muß man natürlich erst zu dem Element hinscrollen und den entsprechenden View Port erreichen.
$I->scrollTo($startpage::$serviceSection);
Das ist kein Hexenwerk, aber ein Pitfail. Wir sollten das immer ganz machen, da Elemente natürlich in der Hierarchie einer Seite verschoben werden können. Das Betrifft auch den Formular Button in längeren Formularen. Die können zwar ohne Scroll ausgefüllt werden, aber ein Click Event klappt da natürlich nicht. Beim ausfüllen springt der Browser übrigens an die richtige Stelle, da es einem onFocus Befehl entspricht.
Mit der Array Shift Anweisung wird dann das erste Element entfernt. Die Funktionalität des initialen Zustands wird ja mit dem anderen Test abgebildet. Wir brauchen keine redundanten Tests. Das hat zwei Gründe. Erstmal ist es eine unnötige Zeit. Und auf der anderen Seite wollen wir auch im Frontend möglichst eindeutig testen. Also ein Test für ein Feature. In diesem Fall wird es aber trotzdem getan, da es den initialen Zustand des Elements beschreit und so bei einem Fehler vorher abgebrochen wird.
Mit grabMultiple ist es uns ja möglich gezielt auf Attribute zuzugreifen. In unserem Beispiel holen wir uns einmal die einzelnen Navigationspunkte und auch die angezeigten Elemente.
$anchors = $I->grabMultiple($startpage::$servicesNavigation, 'href');
$contentItems = $I->grabMultiple($startpage::$servicesItems, 'id');
So können wir mit einer Inerator Variable als $key immer das passende Element zum Navigationspunkt holen. Dann wird hier geklickt und darauf gewartet, daß das passende Element sichtbar wird. Darauf holen wir uns alle Items in ihrem aktuellen Zustand.
$actualContentItems = $I->grabMultiple($startpage::$servicesItems, 'id');
Die anderen sollen ja alle unsichtbar sein. Das kontrollieren wir mit cantSeeElement. Damit unser aktuelles Event aber nicht kontrolliert wird nutzen wir hier bei der Validierung ein continue. Hier brauchen wir mit canSeeElement keine weitere Assertion, da wir schon wissen, daß dieses Element sichtbar geworden ist. Am Ende wird dann noch einmal die Fuktion des ersten Elements geprüft. Hier muss auch wieder hochgescrollt werden, da das erste Element bei der aktuellen Anzahl der Elemente außerhalb des sichtbaren Bereichs liegt.
Das Error Potential und die Folgen – Lohnt sich der Test überhaupt
Lohnt das diesen Test zu schreiben oder kann man das nicht einfach manuell testen? Ehrlich gesagt teste ich im Frontend auch nicht so viele Dinge. Das Kontaktformular ist wichtig und es gibt hier einen Integrationstest, der gleich nachschaut, ob alles korrekt in die DB eingetragen wurde. Für mich ist es schwer Traffic zu bekommen und ein möglicher Kunde für eine Schulung darf mir einfach nicht entgehen, wenn ausgerechnet bei mir ein Formular nicht funktioniert. Tatsächlich spielt der Slider bei mir eine wichtige Rolle. Wenn ich mit HR Teams im Zweitkontakt über die Leistungen eines Events spreche, dann führe ich sie am Telefon auf den Multislider auf der Startpage der Never Code Alone Seite. Hier gehe ich dann auf die einzelnen Punkte ein und kann auch mit den Referenzen den genauen Leistungsumfang erklären. Und als der einmal ausgefallen war und ich noch keine GitLab Pipeline hatte, die das jedes mal checked habe ich das dann noch immer manuell vor den Anrufen gemacht. Unnötig und nervig. Und da auch kein CMS das Element redaktionsfreundlich abbilden kann wird es eben auch manuell programmiert. Hier kann immer mal bei Copy & Paste Aktionen irgendwas vergessen werden anzupassen.Und da ich keine JS Linter einsetze, wird das hier auch direkt abgebildet. Ob sich jetzt der einzelne Test schon lohnt muß jeder für sich selber wissen. Aber in Summe wird hier echt viel getestet. Das wäre manuell für mich unmöglich. Dafür habe ich leider gar keine Zeit 😉
Was will man mit Frontend Tests eigentlich erreichen – Das Frontend ist die Summe aller Prozesse
Was lernen wir aus diesem Codeception Tutorial? Sind wir mal ehrlich zu uns selbst. Wir testen manuell Internetseiten, ob sie laufen. End-to-End Tests sagt man nach, daß sie sehr langsam sind. Dabei sind sie mehr als 8 mal so schnell wie manuelle Tests. Die Seite von Never Code Alone ist technisch recht anspruchsvoll. Das Formular läuft über eine API und hat einen integrierten Spamschutz. Und dann werden über Webservices aktuelle Videos von YouTube, Tweets von Twitter und auch die letzten Blog Posts von WordPress geladen. Die Social Media Services brauchen hier Credentials für die Authentifizierung, die über Rancher Export Environment Variablen geladen werden. Social Media Env Vars
7 Kommentare
[…] […]
[…] 10. November 2019 […]
[…] werden in Duisburg und in Köln stattfinden. Dabei wird es in allen Events ausschließlich um die Programmiersprache PHP gehen. Hier hat Roland Golla – Gründer von Never Code Alone – seine eigenen […]
[…] rumspielen und die Symfony Dependency Injection in Verbindung mit Web APIs als Services vom Know How her […]
[…] des Shops sicher. Dies können sowohl Unit Tests als auch Akzeptanztest sein, welche dann durch ein Testframework durchgeführt werden. Laufen die Test auf allen Applikationsservern durch, sind wir ready to roll […]
[…] Vor allem außerhalb der eigentlichen logischen Programmierung mit PHP und Javascript. Mit dem PHP Testing Framework Codeception habe ich meine ersten großen Schritte für eine eigene PhpStorm Live Templates Kollektion gemacht. […]
[…] und Refactoring” durchführen. Darüber hinaus konnte ich persönlich 3 Talks zu den Themen Codeception Website Testing, Gesundheit und Arbeitsschutz in der IT sowie Clean Code auf dem TYPO3 Camp präsentieren. Für […]