2010-01-20 13 views
13

Ich versuche, Unit-Tests für die offensichtlichen Positive, die es eingeführt wird, und ich versuche, einen Unit-Test für eine Klasse zu schreiben, schrieb ich neulich. (Ich weiß, das ist das Gegenteil von TDD, bitte tragen Sie mit mir)PHPUnit-Test Frage - Wie Unit-Test meine Klasse

Meine Klasse, Image, wird in Verbindung mit einigen anderen für die Bildbearbeitung verwendet.

Image im Wesentlichen Wraps eine GD-Bild-Ressource und speichert Daten mit ihm. wenn die Größe verändert wird zum Beispiel eine Instanz von Image immer enthält sein gegenwärtiger Zustand, das heißt seine neue Breite/Höhe, die ursprünglichen Bilddaten usw.

Die Image Klasse enthält auch Methoden für,

  • selbst erstellen aus einer Datei, String-Daten oder URL, z $image->loadFromPath()
  • Erstellen einer neuen GD-Bildressource aus den Eigenschaften der aktuellen Instanz Image, z. für die Bildgrößenänderung Hintergrund Transparenz usw.
  • Klonen der GD Bildressource für den Einsatz in den Klassen zur Manipulation

Was mit ich bin zu kämpfen ist, wie Unit-Test diese Klasse richtig mit PHPUnit zu halten. Ich habe etwas gelesen und ich habe ein paar widersprüchliche Ideen, wie ich es angehen kann und ich weiß nicht, was richtig ist. Ich,

  1. einen Test für jede Methode der Klasse schreiben. Ich habe irgendwo gelesen, dass ich jede Methode testen sollte. Einige der Methoden führen jedoch andere (zu Recht, kann ich hinzufügen), so dass Sie dann eine Kette von Abhängigkeit haben. Aber ich lese auch, dass jeder Unit-Test unabhängig von dem anderen sein sollte. Was mache ich, wenn das der Fall ist?
  2. Schreiben Sie jeden Test als eine Nutzungsroute der Klasse. Ich habe auch irgendwo gelesen, dass jeder Test stattdessen 1 Pfad/Nutzungsroute darstellen sollte, die Sie mit der Klasse belegen können. Wenn Sie also jede Verwendung abdecken, erhalten Sie letztendlich eine vollständige Codeabdeckung.

Also, welche von diesen ist richtig, wenn überhaupt?

+0

Kennen Sie die Codeabdeckung? IMO ist es wichtiger, jede Codezeile mindestens einmal auszuführen, anstatt einen Test für jede einzelne Methode zu erstellen, was nicht immer aus dem von Ihnen genannten Grund notwendig ist. – Franz

+0

+1 für den Einstieg in UnitTests – Gordon

+0

Ich weiß, welche Codeabdeckung ja ist, und dass Sie auf 100% zielen sollten, was bedeutet, dass jede Zeile mindestens einmal ausgeführt werden sollte. Es ist also definitiv besser, den Testfall zu schreiben, in dem jeder Test eine Aktion ist, die Ihre Klasse durchführt, und nicht jeder Test für eine bestimmte Methode? –

Antwort

8

Komponententests sollten geschrieben werden, um die öffentliche Schnittstelle einer Klasse zu bewerten. Ihr Testfall sollte die Klasse so verwenden, wie Sie sie in Ihrem Programm verwenden möchten. Die Idee hier ist, das Verhalten (entweder erwartete, unerwartete oder Randbedingungen) der Klasse zu testen.

Beide von Ihnen geposteten Ideen sind korrekt. Theoretisch sollten Sie genügend Testfälle (Routen durch Ihren Code) haben, damit alle Ihre Methoden in der Klasse ausgeführt werden.

Wie bereits erwähnt, 100% Testabdeckung ist ein nettes Ziel, aber nicht immer realistisch.

Auch bei GD sollten Sie vorsichtig sein, wenn Sie Komponententests schreiben, die die Funktionalität von GD testen (es wurde bereits getestet, Sie müssen keine Zeit damit verschwenden, es erneut zu testen). Ich würde read up on mit PHPUnit Mocks und Stubs (und spottet das Dateisystem) in der PHPUnit-Handbuch.

Hier ist, was ein Beispiel Test aussehen könnte:

public function testImageIsResized() 
{ 
    $image = new Image(); 
    $image->loadFromPath('some/path'); 
    $image->resize(200, 300); 
    $this->assertEquals(200, $image->getWidth()); 
    $this->assertEquals(300, $image->getHeight()); 
} 

nun abhängig von dem erwarteten Verhalten der Bildklasse, könnte dieser Test ohne Probleme passieren, oder es könnte scheitern, weil es die neuen Dimensionen erwartet wurde proportional zu den ursprünglichen Bildmaßen zu beschränken. Aber wir haben die interne Methode, die im Test selbst nach dieser Einschränkung sucht, nicht explizit aufgerufen.

+0

So ziemlich meine Gedanken jetzt! Danke für die Zusammenfassung –

5

Sie können covers annotation verwenden, um anzugeben, ob ein Test mehrere Methoden umfasst. Wenn also eine Ihrer Methoden eine andere Methode aufruft, können Sie die Annotation einfach zum Docblock des Tests hinzufügen und sie wird Ihren Code-Coverage-Statistiken hinzugefügt, z.

/** 
* @test 
* @covers MyClass::something() 
* @covers MyClass::_somethingElse() 
*/ 
public function somethingWorksAsExpected() 
{ 
    $this->assertSame($expected, $this->testObject->something()); 
} 

Für persönliche Projekte ist 100% Code-Abdeckung in Ordnung. Ich habe jedoch Gespräche auf Konferenzen gesehen, bei denen 100% bezweifelt werden, dass sie notwendig sind. Trotz all der Vorteile brauchen Tests Zeit, um zu schreiben, und in einem budgetierten Projekt könnte es ausreichen, nur 80/20 zu testen und unkritische Funktionen mit niedriger Priorität Ihrer App auszulassen.

Wie Sie Ihre Klasse testen, sehen Sie sich das Kapitel Behaviour Driven Development in the PHPUnit Manual an. In Ihrem Fall würde ich die Funktionalität testen, die Sie in Ihrer Frage beschrieben haben.

0

Stephen Melrose sagte:

jedoch einige der Methoden laufen andere (zu Recht so kann ich noch hinzufügen), sodass Sie dann eine Kette von Abhängigkeiten haben. Aber ich auch gelesen, dass jede Einheit Test sollte vom anderen unabhängig ist

Test-Unabhängigkeit nicht um nicht den gleichen Code zu testen zweimal, es geht darum, ob das Ergebnis (oder fehlende Ergebnis) einen Test beeinflusst das Ergebnis eines anderen. Wenn Ihr erster Test einige Daten einfügt und dann fehlschlägt, bevor er diese Daten entfernen kann, erhält Ihr zweiter Test möglicherweise andere Ergebnisse als erwartet. Im Idealfall sollten Sie in der Lage sein, Ihre Tests in zufälliger Reihenfolge auszuführen oder einige und nicht andere auszuführen.