
Codeception - Wie man automatische Tests startet
Wenn Sie unsere vorherigen Beiträge gelesen haben, wissen Sie bereits sehr gut, wie Sie ein Projekt in der Docker-Konsole starten können. Wenn Sie es noch nicht getan haben, sollten Sie mit diesem Artikel beginnen, da wir für den Zweck dieses Artikels davon ausgehen, dass Ihr Projekt in der Docker-Konsole bereits läuft. Alle unten ausgeführten Befehle beziehen sich daher darauf. In diesem Artikel möchten wir Sie in die Welt der automatischen Tests mit Codeception einführen, basierend auf dieser Art von Projekt. Natürlich muss nicht jeder alle Tests in seinen Projekten automatisieren, aber wenn dies nicht zu viel Arbeit erfordert, wetten wir, dass viele Leute zumindest ein Set von „Smoke Tests“ positiv betrachten werden.
Bei Droptica versuchen wir, die beste Drupal-Agentur auf dem Markt zu sein, und wir glauben fest daran, dass automatisierte Tests uns dabei helfen, dies zu erreichen. Sie reduzieren drastisch die Anzahl der Fehler. Wir pflegen Projekte, bei denen monatelang kein einziger Fehler in die Produktion gelangt ist. Aber genug über uns. Sehen wir uns an, wie Sie Codeception verwenden können.
Was ist Codeception?
Codeception ist ein Framework, das für die Erstellung von Tests verwendet wird, einschließlich Unit-Tests, funktionaler Tests und Akzeptanztests. Trotz der Tatsache, dass es auf PHP basiert, benötigt der Benutzer nur grundlegende Kenntnisse, um mit dem Framework zu beginnen, dank des Sets benutzerdefinierter Befehle, die Codeception bietet. Natürlich gilt: Je mehr Sie testen möchten, desto mehr sollten Sie über PHP-Entwicklung und die Struktur von automatischen Tests lernen. In Codeception werden Tests im BDD-Stil (Behaviour Driven Development) geschrieben – eine Reihe von kurzen Geschichten, die uns über das Verhalten des Systems erzählen, wenn etwas Spezifisches passiert.
Installation
Wir haben bereits ein fertiges Codeception-Image, sodass Sie nichts installieren müssen. Laden Sie einfach die Dateien für unser Projekt herunter (natürlich ist mit „unserem Projekt“ hier das Projekt gemeint, das auf dem Artikel über die Grundlagen der Docker-Konsole basiert). Führen Sie dazu einfach den folgenden Befehl im Projektordner aus:
docker-console init-tests --tpl drupal7
oder für ein Projekt mit Drupal 8
docker-console init-tests --tpl drupal8
Nach der Ausführung wird ein „Tests“-Ordner mit einer installierten und einsatzbereiten Testumgebung erstellt. Die restliche Konfiguration wird für Drupal 7 und 8 gleich sein (abgesehen von zusätzlichen Modulen, die für die konkrete Version geschrieben wurden).
Allgemeine Konfiguration
Die allgemeinen Konfigurationsdaten werden in der Datei codeception.yml gespeichert, die mehr oder weniger wie das untenstehende Beispiel aussehen sollte. Mit der Datei können wir Projektpfade konfigurieren, Speicherkapazitätsgrenzen erhöhen, eine Standardkonfiguration für ein spezifisches Modul festlegen usw. An diesem Punkt müssen Sie hier nichts einstellen, damit das Projekt reibungslos funktioniert.
Detaillierte Konfiguration
Zusätzlich zum Hauptkonfigurationsdatei hat jede Test-Suite ihre eigene Konfigurationsdatei, wie z.B. acceptance.suite.yml. Hier erstellen wir eine Testerklasse, die die genauen Module spezifiziert, die wir während eines Tests verwenden können und – falls erforderlich – es uns erlaubt, die Einstellungen aus der allgemeinen Datei zu überschreiben. Wir müssen im Moment hier nichts ändern; jedoch möchte ich auf die PhpBrowser-Einstellungen hinweisen. Die URL (http://web), die hier gesetzt ist, muss nicht geändert werden, da der Name „web“ sich auf den Namen unseres Docker-Containers bezieht, der unsere Website enthält. Die „auth“-Variable bezieht sich auf den Benutzernamen und das Passwort, mit denen wir unsere Site über .htaccess sichern können. Da wir solche Sicherheitsmaßnahmen in unserem Projekt derzeit nicht verwenden, können Sie diese Zeile aus der Konfigurationsdatei löschen. Die Diskussion der verbleibenden Module ist ein weitaus komplexeres und umfangreiches Thema, das ich im kommenden Artikel zu behandeln versuchen werde.
Eine kurze Einführung in Tests
Wie ich bereits zuvor erwähnt habe, können Sie mit Codeception Unit-, funktionale und Akzeptanztests schreiben.
In unserem Fall haben wir letztere nach dem verwendeten Treiber aufgeteilt. Der Hauptgrund für eine solche Aufteilung war die schnellere Testausführungszeit im Falle der Verwendung von PhpBrowser und die Notwendigkeit, WebDriver für Tests zu verwenden, bei denen JavaScript-Funktionen auf der Website eingesetzt wurden.
PhpBrowser |
WebDriver | |
---|---|---|
Browser-Engine | Guzzle + Symfony BrowserKit |
Chrome oder Firefox |
JavaScript | NEIN | JA |
Sichtbarkeit von Elementen auf der Website |
Der Text ist sichtbar, wenn er im Quelltext enthalten ist |
Der Text ist nur sichtbar, wenn er für den Benutzer sichtbar ist, der die Website besucht |
Lesen von HTTP Antwort-Headern |
JA | NEIN |
Testgeschwindigkeit | Mittel | Langsam |
Die folgende Tabelle zeigt die allgemeinen Unterschiede zwischen den verschiedenen Testtypen. Wir haben uns auch entschieden, JS-fähige Tests hinzuzufügen, die ebenfalls zu den Akzeptanztests gehören; jedoch werden im Gegensatz zur Akzeptanzsuite, die mit PhpBrowser durchgeführt wird, JS-fähige Tests mit WebDriver im Chrome- oder Firefox-Webbrowser gestartet (wie bereits erwähnt, ist dies unsere Konfiguration und natürlich steht Ihnen nichts im Weg, WebDriver zur Akzeptanzsuite hinzuzufügen).
Unit | Funktional | Akzeptanz | JS-fähig | |
---|---|---|---|---|
Umfang | PHP-Klasse | PHP-Framework | Website geöffnet in einem Webbrowser (sichtbares HTML) |
Website, wie sie vom Endbenutzer gesehen wird |
JavaScript | NEIN | NEIN | NEIN | JA |
Webserver erforderlich | NEIN | NEIN | JA | JA |
Testgeschwindigkeit | HOCH | HOCH | MITTEL | NIEDRIG |
Konfigurationsdatei | unit.suite.yml | functional.suite.yml | acceptance.suite.yml | js_capable.suite.yml |
Selektoren
Die letzte Sache, die ich besprechen möchte, bevor wir zu den Beispielen für das Schreiben von Tests übergehen, sind Locator, also die Methode, mit der Codeception die Elemente findet, die wir während unserer Tests verwenden möchten. In Codeception können Sie die Elemente mithilfe von finden:
- ID, zum Beispiel „#test“, was <div id=”test”> entspricht
- Klassen, zum Beispiel „.test“, was <div class=”test”> entspricht
- Namen, zum Beispiel „test“, was <div name=”test”>, <input value=”test”> oder einfach dem sichtbaren Text auf der Website entspricht.
- CSS, zum Beispiel „input[value=test ]“, was <input value="test"> entspricht
- XPath, zum Beispiel //input[@type='submit'][contains(@value, 'test')]"], was <input type="submit" value="foobar"> entspricht
Sie können auch komplexere Locator verwenden, die detaillierter beschrieben werden unter: http://codeception.com/docs/reference/Locator
Unabhängig davon, wie Sie Ihr Element lokalisieren werden, sollten Sie immer anstreben, dies auf die expliziteste und eindeutigste Weise zu tun.
Akzeptanztests
Wenn Sie Testfälle haben, die Sie immer durchklicken müssen, bevor Sie die Website bereitstellen, um zu sehen, ob sie ordnungsgemäß funktioniert, dann haben Sie tatsächlich perfekte Kandidaten für die Automatisierung und die Platzierung der Tests im Codeception Akzeptanztestordner. Im Falle unserer Konfiguration enthält der Akzeptanzordner alle Tests, die ohne JavaScript durchgeführt werden können, da wir in diesem Fall PhpBrowser verwenden (das ist nicht notwendig, aber sicherlich schneller). Mit diesen Tests haben wir viele hilfreiche und bereits definierte Funktionen, deren Liste und Beschreibungen Sie auf der Website finden können: http://codeception.com/docs/modules/PhpBrowser
Als Beispiel haben wir hier einen Test, bei dem wir uns mit dem Administrator-Konto anmelden und sehen, ob der Text eines der Artikel auf der Startseite sichtbar ist.
<?php
class ExampleAcceptanceTestCest
{
public function _before(AcceptanceTester $I) {
}
public function _after(AcceptanceTester $I) {
}
/** TESTS */
/**
* @param \AcceptanceTester $I
*
*/
public function exampleTest(AcceptanceTester $I) {
$I->wantTo('Test - Ich kann mich als Admin anmelden und einen Artikel sehen');
$I->amOnPage('/');
$I->fillField('#edit-name', 'admin');
$I->fillField('#edit-pass', 'admin');
$I->click('Anmelden');
$I->amOnPage('/');
$I->see('Droptica sięga korzeniami roku 2008, kiedy to jeden ze współzałożycieli stworzył swoją pierwszą firmę programistyczną openBIT');
$I->amOnPage('/user/logout');
}
}
JS-fähige Tests
Zusätzlich haben wir für unsere Bedürfnisse die js_capable-Suite hinzugefügt, in der wir Akzeptanztests schreiben, die JavaScript erfordern. Im Allgemeinen sollten wir in der Lage sein, den Test aus dem Akzeptanzordner zu kopieren, ihn in js_capable einzufügen, und er sollte sofort funktionieren; jedoch müssen wir bedenken, dass das Programm in diesem Fall jedes Element genau so sieht, als wäre es ein Benutzer. Daher würde das Hinzufügen von display:none in CSS dieses Element aus dem Sichtfeld entfernen, während es im Fall von PhpBrowser weiterhin sichtbar bleibt, da es im HTML-Code enthalten ist. Zum Vergleich können Sie die Liste der verfügbaren Funktionen für WebDriver lesen: http://codeception.com/docs/modules/WebDriver
Bevor ich Ihnen einen Beispieltest zeige, möchte ich auch die Konfiguration solcher Tests erörtern. Um sie zu starten, müssen Sie weder WebDriver noch einen Webbrowser lokal installiert haben, da alles bequem in einem Docker-Container sitzt. Direkt nach der Initialisierung des Projekts mit Tests ist die Umgebung bereit, sie in Chrome mit dem neuesten WebDriver zu starten. Wenn Sie jedoch sehen möchten, wie Ihre Tests in Firefox laufen, müssen Sie es an zwei Stellen ändern: Zuerst müssen Sie „chrome“ in der js_capable.suite.yml-Datei durch „firefox“ ersetzen.
Dann müssen Sie das Selenium-Image für eines ändern, das Firefox enthält. Sie können dies tun, indem Sie die Datei dc_settings.py in einem Docker-Konsole-Ordner bearbeiten, wo Sie „standalone-chrome“ durch „standalone-firefox“ ersetzen sollten.
Mehr dazu können Sie erfahren unter:
https://hub.docker.com/r/selenium/standalone-chrome/
https://hub.docker.com/r/selenium/standalone-firefox/
Nun ist es Zeit für ein Beispiel, das Knoten wie den Artikel und die Basisseite hinzufügt.
<?php
class JSCentreTestsCest
{
public function _before(JSCapableTester $I) {
}
public function _after(JSCapableTester $I) {
}
/** TESTS */
/**
* @param \JSCapableTester $I
*
*/
public function addArticle(JSCapableTester $I) {
$I->wantTo('Test - Ich füge Artikel hinzu');
$I->amOnPage('/');
$I->fillField('#edit-name', 'admin');
$I->fillField('#edit-pass', 'admin');
$I->click('Anmelden');
$I->amOnPage('/node/add/article');
$I->fillField('#edit-title', 'Testartikel');
$I->fillField('#edit-body-und-0-value', 'Testtext im Artikeltitel');
$I->click('#edit-submit');
$I->see('Artikel Testartikel wurde erstellt.');
$I->see('Testtext im Artikeltitel');
$I->amOnPage('/user/logout');
}
/**
* @param \JSCapableTester $I
*
*/
public function addPage(JSCapableTester $I) {
$I->wantTo('Test - Ich füge eine Basisseite hinzu');
$I->amOnPage('/');
$I->fillField('#edit-name', 'admin');
$I->fillField('#edit-pass', 'admin');
$I->click('Anmelden');
$I->amOnPage('/node/add/page');
$I->fillField('#edit-title', 'Testbasis-Seite');
$I->fillField('#edit-body-und-0-value', 'Testtext im Seitentitel');
$I->click('#edit-submit');
$I->see('Basis-Seite Testbasis-Seite wurde erstellt.');
$I->see('Testtext im Seitentitel');
$I->amOnPage('/user/logout');
}
}
Wenn Sie mehr über Akzeptanztests erfahren möchten, sollten Sie unbedingt folgende Seite besuchen:
http://codeception.com/docs/03-AcceptanceTests
Funktionale Tests
Funktionale Tests werden in einer Weise geschrieben, die den Akzeptanztests sehr ähnlich ist. Der Hauptunterschied besteht darin, dass sie nicht auf einem Webserver gestartet werden müssen, was sie erheblich schneller macht. Als zusätzlicher Vorteil bieten sie auch zusätzliche Befehle, die das Testen von Frameworks wie Symfony, Laravel5, Yii2, Yii, Zend Framework 2, Zend Framework 1.x und Phalcon ermöglichen. Tatsächlich macht es nur Sinn, funktionale Tests zu schreiben, wenn Sie eines dieser Frameworks verwenden, es sei denn, Sie schreiben die notwendigen Funktionen selbst.
Im Folgenden zeige ich Ihnen, wie ein solcher Test aussehen könnte.
Bevor wir beginnen, einen Test zu schreiben, müssen wir im funktionalen.suite.yml die Möglichkeit hinzufügen, das Db-Modul für funktionale Tests zu verwenden. Nach dieser Änderung sollte die Datei wie folgt aussehen:
Jetzt schreiben wir einen Test, der überprüft, ob die Datenbank Knoten enthält (das Hinzufügen von Knoten könnte auch in diesem Test enthalten sein).
<?php
use Drupal\Pages\Page;
use Codeception\Util\Shared\Asserts;
class ExampleFunctionalTestCest
{
use Asserts;
public function _before(FunctionalTester$I) {
}
public function _after(FunctionalTester $I) {
}
/** TESTS */
/**
* @param \FunctionalTester $I
*/
public function exampleTestOfText(FunctionalTester $I) {
$I->wantTo('Test - Ich kann einen Knoten in der Datenbank sehen');
$I->haveInDatabase('node', array('type' => 'article', 'title' => 'WSZYSTKO, CO CHCIELIBYŚCIE WIEDZIEĆ O REKRUTACJI W DROPTICE'));
$I->haveInDatabase('node', array('type' => 'page', 'title' => 'Testseite'));
}
}
Mehr über funktionale Tests können Sie hier lesen: http://codeception.com/docs/04-FunctionalTests
Unit-Tests
Wenn Sie in der Vergangenheit PHPUnit-Unit-Tests geschrieben haben, müssen Sie nichts neu lernen und können die gleiche Syntax wie zuvor verwenden.
In meinem Beispiel wird es notwendig sein, die Verwendung von Drupal-Befehlen zu ermöglichen, um sicherzustellen, dass dieser Test ordnungsgemäß funktioniert. Um dies zu tun, werde ich ein Modul in der Datei unit.suite.yml entsperren. Nachdem dies geschehen ist, sollte die Datei wie im untenstehenden Beispiel aussehen:
Jetzt können wir einen Test schreiben, der überprüft, ob ein Modul für Backup und Migration in Drupal aktiviert ist.
<?php
class ExampleUnitTest extends \Codeception\Test\Unit
{
/**
* @var \UnitTester
*/
protected $tester;
protected function _before()
{
}
protected function _after()
{
}
/** TESTS */
public function testModulesEnabled()
{
$modules[] = 'backup_migrate';
foreach ($modules as $modules_name) {
$result = module_exists($modules_name);
$this->assertEquals(TRUE, module_exists($modules_name));
}
}
}
Wenn Sie mehr über Unit-Tests erfahren möchten, sollten Sie besuchen: http://codeception.com/docs/05-UnitTests
Tests starten
Nachdem alle Tests geschrieben und bereit sind, bleibt nur noch, sie zu starten und ihre Ergebnisse zu beobachten. Denken Sie daran, dass Sie, bevor Sie die Tests starten, die Projektcontainer starten müssen (dcon up). Sie können die Tests auf mehrere Arten starten:
- Alle von uns geschriebenen Tests,
dcon test
- nur ein Satz von Tests, z.B.
dcon test acceptance
- eine einzelne Datei mit Tests, z.B.
dcon test acceptance/ExampleFile.php
- ein einzelner Test, z.B.
dcon test acceptance/ExampleFile.php::ExampleTest
Nach dem Start der Tests mit dem Befehl „dcon test“ sollten Sie die Ausführung der Tests sehen und am Ende etwas Ähnliches wie das untenstehende Bild sehen.
Berichte
Natürlich hinterlässt Ihnen Codeception nicht nur, was Sie in der Konsole sehen. Nach Abschluss der Tests enthält der Output-Ordner einen Bericht im XML- und HTML-Format. Nach einem Klick auf das Plus-Zeichen neben einem bestimmten Test zeigt der Bericht alle während dieses Tests durchgeführten Schritte an.
Lassen Sie uns nun versuchen, etwas auf unserer Website oder in unseren Tests zu ändern, um einen Fehler zu erzeugen. Wie Sie sehen können, markiert Codeception bei einem Fehler genau den Schritt, bei dem der Fehler aufgetreten ist. Da der Test im Browser unter Verwendung des WebDrivers durchgeführt wurde, haben wir zusätzlich einen Screenshot beigefügt, zusammen mit einer kurzen Beschreibung des Problems. Wenn einer der Akzeptanztests fehlschlägt, erhalten Sie eine HTML-Datei mit dem Code zum Zeitpunkt des Fehlerauftretens.
Projektdateien
Sie können die in diesem Artikel beschriebenen Beispiele aus dem Produkt-Repository herunterladen und den Branch auf Codeception-start ändern.
Projekt-Repository:
https://github.com/DropticaExamples/docker-console-project-example
Datenbank-Dump:
https://www.dropbox.com/s/tcfkgpg2ume17r3/database.sql.tar.gz?dl=0
Projektdateien:
https://www.dropbox.com/s/tnl0ftfluyr5j7p/files.tar.gz
Fazit
Ich hoffe, dass Sie nach dem Lesen dieses Textes wissen, wie Sie Ihr Abenteuer mit Codeception beginnen und dass ich Sie zumindest ein wenig dazu ermutigt habe. Zum Schluss gebe ich Ihnen einige Tipps und Richtlinien zum Schreiben von Tests:
- Achten Sie immer auf Überprüfungen in Tests, denn ein Test, der nichts überprüft, ist kein Test,
- versuchen Sie immer, stabile Tests zu schreiben (wählen Sie Element-Selektoren so, dass der Test sie immer explizit lokalisieren kann – niemand möchte falsche Positiva und Negative haben),
- versuchen Sie, mehrere kleinere Tests zu schreiben, anstatt einen großen, denn wenn etwas kaputt geht, haben die verbleibenden Tests die Möglichkeit, die Seite weiter zu überprüfen,
- versuchen Sie, unabhängige Tests zu schreiben, und wenn dies nicht möglich ist, informieren Sie das System (z.B. durch Verwendung der @depends-Anmerkung), damit es bei einem Fehlschlagen eines Tests zu einem anderen Test übergehen kann,
- versuchen Sie nicht, alles, was Sie tun, zu automatisieren – das ist etwas für einen anderen Artikel oder sogar ein Buch, aber egal, was Sie tun, bevor Sie jeden Test schreiben, sollten Sie überlegen, ob Sie ihn tatsächlich benötigen,
- wenn Sie ein Stück Code mehr als einmal verwenden, denken Sie darüber nach, es in eine separate Funktion auszulagern,
- versuchen Sie, keine festen Selektoren und URLs in Ihren Tests zu verwenden (verwenden Sie das Page Object Pattern – wir werden versuchen, bald mehr darüber zu schreiben).