Verschiedene Testmethoden
Definieren Sie zunächst, was Sie tun: Unit-Test oder Integrationstest . Die Anzahl der Schichten ist für Komponententests irrelevant, da Sie höchstwahrscheinlich nur eine Klasse testen. Den Rest verspotten Sie. Für Integrationstests ist es unvermeidlich, dass Sie mehrere Ebenen testen. Wenn Sie über gute Komponententests verfügen, besteht der Trick darin, die Integrationstests nicht zu komplex zu gestalten.
Wenn Ihre Komponententests gut sind, müssen Sie beim Integrationstest nicht alle Details wiederholen.
Begriffe, die wir verwenden, sind ein bisschen plattformabhängig, aber Sie können sie in fast allen Test- / Entwicklungsplattformen finden:
Beispielanwendung
Je nach verwendeter Technologie können die Namen unterschiedlich sein, ich werde dies jedoch als Beispiel verwenden:
Wenn Sie eine einfache CRUD-Anwendung mit Modell Product, ProductsController und einer Indexansicht haben, die eine HTML-Tabelle mit Produkten generiert:
Das Endergebnis der Anwendung ist eine HTML-Tabelle mit einer Liste aller aktiven Produkte.
Unit-Test
Modell
Das Modell kannst du ganz einfach testen. Es gibt verschiedene Methoden dafür; Wir verwenden Vorrichtungen. Ich denke, das nennt man "gefälschte Datensätze". Also erstellen wir vor jedem Test die Tabelle und geben die Originaldaten ein. Die meisten Plattformen haben Methoden dafür. Zum Beispiel in Ihrer Testklasse eine Methode setUp (), die vor jedem Test ausgeführt wird.
Dann führen wir unseren Test durch, zum Beispiel: testGetAllActive- Produkte.
Also testen wir direkt in eine Testdatenbank. Wir verspotten die Datenquelle nicht. Wir machen es immer gleich. Dies ermöglicht es uns beispielsweise, mit einer neuen Version der Datenbank zu testen, und es treten Fragen auf.
In der realen Welt kann man nicht immer einer 100% igen Einzelverantwortung folgen . Wenn Sie dies noch besser machen möchten, könnten Sie eine Datenquelle verwenden, die Sie verspotten. Für uns (wir verwenden ein ORM), das das Gefühl hat, bereits vorhandene Technologie zu testen. Außerdem werden die Tests viel komplexer und testen die Abfragen nicht wirklich. Also halten wir es so.
Die fest codierten Daten werden separat in den Fixtures gespeichert. Das Fixture ist also wie eine SQL-Datei mit einer create table-Anweisung und Einfügungen für die von uns verwendeten Datensätze. Wir halten sie klein, es sei denn, es besteht ein tatsächlicher Testbedarf mit vielen Aufzeichnungen.
class ProductModel {
public function getAllActive() {
return $this->find('all', array('conditions' => array('active' => 1)));
}
}
Regler
Der Controller benötigt mehr Arbeit, da wir das Modell damit nicht testen wollen. Also verspotten wir das Modell. Das heißt: Wir testen die Methode: index (), die eine Liste von Datensätzen zurückgeben soll.
Also verspotten wir die Modellmethode getAllActive () und fügen feste Daten hinzu (zum Beispiel zwei Datensätze). Jetzt testen wir die Daten, die der Controller an die Ansicht sendet, und vergleichen, ob wir diese beiden Datensätze wirklich zurückbekommen.
function testProductIndexLoggedIn() {
$this->setLoggedIn();
$this->ProductsController->mock('ProductModel', 'index', function(return array(your records) ));
$result=$this->ProductsController->index();
$this->assertEquals(2, count($result['products']));
}
Das ist genug. Wir versuchen, dem Controller so wenig Funktionalität wie möglich hinzuzufügen, da dies das Testen schwierig macht. Aber natürlich ist immer etwas Code drin. Zum Beispiel testen wir Anforderungen wie: Zeigen Sie diese beiden Datensätze nur an, wenn Sie angemeldet sind.
Der Controller benötigt also normalerweise einen Schein und ein kleines Stück fest codierter Daten. Für ein Login-System vielleicht ein anderes. In unserem Test haben wir eine Hilfsmethode dafür: setLoggedIn (). Das macht es einfach, mit oder ohne Login zu testen.
class ProductsController {
public function index() {
if($this->loggedIn()) {
$this->set('products', $this->ProductModel->getAllActive());
}
}
}
Ansichten
Views testen ist schwer. Zuerst trennen wir die sich wiederholende Logik. Wir setzen es in Helfer und testen diese Klassen streng. Wir erwarten immer die gleiche Leistung. Beispiel: generateHtmlTableFromArray ().
Dann haben wir einige projektspezifische Ansichten. Diese testen wir nicht. Es ist nicht wirklich erwünscht, solche Einheiten zu testen. Wir bewahren sie für Integrationstests auf. Da wir einen Großteil des Codes in Views herausgenommen haben, haben wir hier ein geringeres Risiko.
Wenn Sie anfangen, diese zu testen, müssen Sie Ihre Tests wahrscheinlich jedes Mal ändern, wenn Sie ein Stück HTML ändern, was für die meisten Projekte nicht nützlich ist.
echo $this->tableHelper->generateHtmlTableFromArray($products);
Integrationstests
Abhängig von Ihrer Plattform können Sie hier mit User Stories usw. arbeiten. Es kann webbasiert sein wie Selenium oder andere vergleichbare Lösungen.
Im Allgemeinen laden wir einfach die Datenbank mit den Fixtures und geben an, welche Daten verfügbar sein sollen. Für vollständige Integrationstests verwenden wir im Allgemeinen sehr globale Anforderungen. Also: Produkt auf aktiv setzen und dann prüfen, ob das Produkt verfügbar ist.
Wir testen nicht alles noch einmal, zum Beispiel, ob die richtigen Felder verfügbar sind. Hier testen wir die größeren Anforderungen. Da wir unsere Tests nicht vom Controller oder aus der Sicht duplizieren wollen. Wenn etwas wirklich der Schlüssel / Kernbestandteil Ihrer Anwendung ist oder aus Sicherheitsgründen (das Kennwort ist NICHT verfügbar), fügen wir es hinzu, um sicherzustellen, dass es richtig ist.
Die fest codierten Daten werden in den Fixtures gespeichert.
function testIntegrationProductIndexLoggedIn() {
$this->setLoggedIn();
$result=$this->request('products/index');
$expected='<table';
$this->assertContains($expected, $result);
// Some content from the fixture record
$expected='<td>Product 1 name</td>';
$this->assertContains($expected, $result);
}