2012-04-12 21 views
24

Voglio usare il Test Driven Development il più possibile: è un ottimo modo di lavorare.Come posso testare un controller Symfony2?

Sono turbato dal fatto che i controller Symfony2 creino e restituiscano un nuovo oggetto Response.

Desidero essere in grado di testare un controller da solo.

Come si fa?

È la risposta per creare un controller come oggetto PHP vecchio e semplice, registrarlo come servizio e utilizzare Dipendenza iniezione per passare un nuovo oggetto Response (o uno stabilimento Response) in esso?

+2

Qual è esattamente il problema con esso la restituzione di un oggetto 'Response'? –

+0

Niente. Non mi piace il fatto che un oggetto Response sia stato creato in un controller. Sono un convinto sostenitore della dipendenza da iniezione, e odio vedere la parola chiave "nuova" in qualcosa di diverso da un contenitore DI. Forse quella credenza è sbagliata. –

risposta

51

Normalmente, il controller collega insieme diversi oggetti e li collega nell'ordine corretto. Forse chiama un repository, legge alcuni oggetti e li restituisce attraverso il metodo render. Forse chiama altri Handler/Manager che fanno cose.

Ciò significa che un controller è un componente di alto livello. Molto spesso questo indica che i test funzionali sono in ordine invece dei test unitari. Non dovresti mirare a ottenere una copertura del codice del 100% con i tuoi test unitari. Forse puoi pensarci in questo modo: se collaudi unitamente tutto ciò che il controller chiama (modello, validazione, modulo, repository), cosa potrebbe andare storto? La maggior parte delle volte è qualcosa che si osserva solo quando si utilizzano tutte le classi reali coinvolte durante la produzione.

Vorrei anche sottolineare che TDD non significa che tutto deve essere testato unitamente. Va bene avere alcuni test funzionali per il codice di alto livello. Come detto, se provi i componenti di basso livello con i test unitari, dovresti solo verificare come stanno lavorando insieme, cosa che non puoi testare con i mock perché dici al mock quale sia il valore di ritorno.

Se il controller fa più che collegare parti del sistema, dovresti pensare a rifare il materiale in più classi di basso livello che puoi testare con i test unitari.

Quindi il mio suggerimento sarebbe quello di utilizzare i test funzionali per testare i controller e le unità di test utilizzare per provare il modello e la vostra roba logica di business.

Se si lotta con test funzionali, si può leggere quanto segue:

+0

Ok. Ho pensato che dal momento che il Controller era una classe, doveva essere anche testato su unità. Non mi piace l'idea di scrivere il codice prima di scrivere i test, quindi mi chiedevo se c'era un modo per ridefinire il modo in cui i controller sono usati per essere in grado di testarli. Credo di poter ancora lavorare con TDD scrivendo test funzionali prima di scrivere il controller. –

2

Usa si fa beffe di isolare modelli e altri oggetti da logica del metodo di controllo principale, vedere http://www.phpunit.de/manual/3.7/en/test-doubles.html#test-doubles.mock-objects

penso che nelle versioni precedenti si poteva prendere in giro tutta la classe, ma con le ultime PHPUnit 3.6.10 che ho non è così sembra funzionare. Quindi suppongo che tu rimanga con un modello di iniezione depency

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 - ma questi oggetti (incluso l'oggetto Response) verranno istanziati nel Controller. A meno che non utilizzi il contenitore DI per fornire i modelli e le altre cose per i controller. Forse potrei creare un servizio di Response Factory, e prenderlo dal contenitore DI - in questo modo (il contenitore DI e la factory) potrebbe essere deriso per testare la classe Controller in isolamento. –

0

Lewis - ho pensato di saltare qui. L'approccio sopra riportato consente di replicare la parte migliore della logica delle azioni nei test. Non c'è niente di sbagliato in questo, molti framework (in particolare RSPEC in Rails) in realtà suggeriscono di eseguire sia i test Unit sia gli oggetti Controller e test funzionali. Tuttavia, dato il tuo esempio, penso che salterò il test unitario e andrò per l'approccio funzionale.

Il punto di un test nella mia mente è creare un ambiente in modalità sandbox, eseguire il test e controllare gli effetti collaterali e il risultato diretto. Se arrivi ad un punto in cui la maggior parte del tuo test sta isolando il metodo, allora probabilmente è il momento per un approccio di test diverso o un approccio diverso per scrivere la tua classe. Dato che si tratta di un controller, e per loro natura incollano insieme diversi pezzi dello stack, creerei la sandbox più in alto. In particolare, vorrei utilizzare un approccio come questo:

https://github.com/PolishSymfonyCommunity/SymfonyMockerContainer

lavorato molto per me :)

1

Unit Testing

refactoring del controller di essere servizi: http://symfony.com/doc/current/cookbook/controller/service.html

Poi si può facilmente unità li test.

Functional Testing

Naturalmente (come già detto da altri) è possibile utilizzare la WebTestCase come descritto qui: http://symfony.com/doc/current/book/testing.html#functional-tests

+0

La definizione dei controller come servizi non è ufficialmente raccomandata da Symfony. Sono utilizzati da alcuni sviluppatori per casi d'uso molto specifici, come DDD (design basato sul dominio) e applicazioni di architettura esagonale. –

+0

Chi lo dice? https://symfony.com/doc/current/controller/service.html Il professionista ha superato i truffatori nella propria documentazione. Sono sicuro che i controller saranno supportati nelle versioni future di symfony, quindi non mi preoccuperei troppo di non essere "ufficialmente raccomandato". –

Problemi correlati