2012-04-12 13 views
24

Ich möchte Test Driven Development so viel wie möglich verwenden - es ist eine großartige Art zu arbeiten.Wie kann ich einen Symfony2-Controller testen?

Ich bin durch die Tatsache besorgt, dass Symfony2-Controller erstellen und ein neues Response Objekt zurückgeben.

Ich möchte in der Lage sein, einen Controller isoliert zu testen.

Wie machst du das?

Ist die Antwort zum Erstellen eines Controllers als Plain Old PHP-Objekt, registrieren Sie es als Dienst und verwenden Sie Dependency Injection, um ein neues Response Objekt (oder eine Response Fabrik) in es zu übergeben?

+2

Was ist genau das Problem mit ihm ein 'Response' Objekt zurückkehrt? –

+0

Nichts. Ich mag einfach nicht die Tatsache, dass ein Response-Objekt in einem Controller erstellt wird. Ich glaube fest an Dependency Injection, und ich hasse es, das "neue" Schlüsselwort in etwas anderem als einem DI-Container zu sehen. Vielleicht ist dieser Glaube falsch. –

Antwort

51

Normalerweise verstopft Ihr Controller verschiedene Objekte und verbindet sie in der richtigen Reihenfolge. Vielleicht ruft er ein Repository auf, liest einige Objekte und gibt sie durch die Rendermethode zurück. Vielleicht ruft er andere Handler/Manager, die Sachen machen.

Dies bedeutet, dass ein Controller eine Komponente auf hohem Niveau ist. Meistens bedeutet dies, dass Funktionstests anstelle von Komponententests in Ordnung sind. Sie sollten nicht darauf abzielen, mit Ihren Komponententests eine 100% ige Codeabdeckung zu erhalten. Vielleicht können Sie sich das so vorstellen: Wenn Sie alles testen, was der Controller aufruft (Modell, Validierung, Formular, Repository), was könnte schief gehen? Die meiste Zeit ist es etwas, das Sie nur beobachten, wenn Sie alle realen Klassen verwenden, die in der Produktion beteiligt sind.

Ich möchte auch darauf hinweisen, dass TDD nicht bedeutet, dass alles Unit-getestet werden muss. Es ist in Ordnung, einige Funktionstests für den High-Level-Code zu haben. Wie gesagt, wenn Sie die Low-Level-Komponenten mit Komponententests testen, sollten Sie nur testen, wie sie zusammenarbeiten, die Sie nicht mit Mocks testen können, weil Sie den Mocks sagen, was der Rückgabewert ist.

Wenn Ihr Controller mehr als nur Teile des Systems zusammenstellt, sollten Sie darüber nachdenken, das Zeug in mehr Low-Level-Klassen umzuwandeln, die Sie mit Unit-Tests testen können.

Also mein Vorschlag wäre, Funktionstests zu verwenden, um Ihre Controller zu testen und Unit-Tests zu verwenden, um Ihre Modelle und Ihre Geschäftslogik Zeug zu testen.

+0

Okay. Ich dachte, da der Controller ein Kurs war, musste er auch Unit-getestet werden. Ich mag die Idee nicht, Code zu schreiben, bevor ich Tests schreibe, also habe ich mich gefragt, ob es eine Möglichkeit gibt, die Art und Weise, wie Controller verwendet werden, umzuformen, um sie in der Einheit testen zu können. Ich denke, ich kann immer noch mit TDD arbeiten, indem ich Funktionstests schreibe, bevor ich den Controller schreibe. –

2

Verwenden spottet Modelle und andere Objekte aus Haupt-Controller-Methode der Logik zu isolieren, siehe http://www.phpunit.de/manual/3.7/en/test-doubles.html#test-doubles.mock-objects

Ich denke, dass Sie in älteren Versionen ganze Klasse verspotten konnten, aber mit dem neuesten phpunit 3.6.10, dass ich es hat nicht scheinen zu arbeiten. So, ich denke, Sie sind mit Abhängigkeit Injektion Muster verlassen

class objss{ 
    function ss(){ 
     $x = new zz(); 
     var_dump($x->z()); 
    } 
} 



class MoTest extends PHPUnit_Framework_TestCase{ 
    public function setUp(){ 

    } 

    public function testA(){ 
     $class = $this->getMock('zzMock', array('z'), array(), 'zz'); 
     $class->expects($this->any())->method('z')->will($this->returnValue('2')); 

     $obj = new objss(); 
     $this->assertEquals('2', $obj->ss()); 
    } 
} 
+0

Totaly - aber diese Objekte (einschließlich des Response-Objekts) würden im Controller instanziiert werden. Es sei denn, ich verwende den DI-Container, um die Modelle und andere Dinge für die Controller bereitzustellen. Vielleicht könnte ich einen Response-Factory-Service erstellen und ihn aus dem DI-Container holen - so könnte man ihn (den DI-Container und die Fabrik) zum Testen der Controller-Klasse isolieren. –

0

Lewis - ich dachte, dass ich hier springen würde:

Wenn Sie mit funktionalen Tests kämpfen, können Sie das folgende lesen. Der obige Ansatz repliziert den besseren Teil Ihrer Aktionslogik in Ihren Tests. Es ist nichts falsch daran, viele Frameworks (insbesondere RSPEC in Rails) schlagen tatsächlich vor, dass Sie sowohl Komponententests für Ihre Controller-Objekte als auch Funktionstests durchführen. In Anbetracht Ihres Beispiels würde ich jedoch den Komponententest überspringen und den funktionalen Ansatz wählen.

Der Punkt eines Tests in meinem Kopf ist es, eine Sandbox-Umgebung zu erstellen, den Test auszuführen und auf Nebenwirkungen und direkte Ergebnisse zu überprüfen. Wenn Sie einen Punkt erreichen, an dem die meisten Ihrer Tests die Methode isolieren, ist es wahrscheinlich Zeit für einen anderen Testansatz oder einen anderen Ansatz zum Schreiben Ihrer Klasse. Da dies ein Controller ist und von Natur aus verschiedene Teile des Stapels zusammenklebt, würde ich Ihre Sandbox weiter oben auf dem Stapel erstellen. Insbesondere würde ich einen Ansatz wie folgt verwenden:

https://github.com/PolishSymfonyCommunity/SymfonyMockerContainer

große Arbeitete für mich :)

1

Unit Testing

Ihre Controller Refactoring Dienste sein: http://symfony.com/doc/current/cookbook/controller/service.html

Sie dann kann sie einfach testen.

Functional Testing

Natürlich (wie schon von anderen erwähnt) können Sie den WebTestCase verwenden, wie hier beschrieben: http://symfony.com/doc/current/book/testing.html#functional-tests

+0

Die Definition von Controllern als Dienste wird von Symfony nicht offiziell empfohlen. Sie werden von einigen Entwicklern für sehr spezielle Anwendungsfälle wie DDD (domain-driven design) und Hexagonal Architecture verwendet. –

+0

Wer sagt das? https://symfony.com/doc/current/controller/service.html Die Profis sind die Nachteile in ihrer eigenen Dokumentation. Ich bin mir ziemlich sicher, dass Controller als Dienste in zukünftigen Versionen von symfony unterstützt werden, also würde ich mir keine Sorgen machen, dass es "nicht offiziell empfohlen" wird. –