2014-04-29 17 views
7

Dopo aver finalmente superato il mio stupido test, ho la sensazione che non lo stia facendo correttamente.Test di Laravel con PHPUnit e Mockery - Impostazione delle dipendenze sul test del controller

Ho un SessionsController, che è responsabile per la visualizzazione di una pagina di accesso e la registrazione di un utente in.

ho deciso di non utilizzare le facciate in modo che non avrei dovuto estendere TestCase di laravel e prendere un calo di prestazioni sui miei test unitari. Pertanto, ho iniettato tutte le dipendenze attraverso il controller, in questo modo -

SessionsController - Funzione di costruzione

public function __construct(UserRepositoryInterface $user, 
          AuthManager $auth, 
          Redirector $redirect, 
          Environment $view) 
{ 
    $this->user = $user; 
    $this->auth = $auth; 
    $this->redirect = $redirect; 
    $this->view = $view; 
} 

ho fatto la necessaria dichiarazione di variabili e utilizzare gli spazi dei nomi, che io non ho intenzione per includere qui come non necessario.

il metodo di creazione rileva se un utente è autorizzato, se sono quindi li reindirizzo alla home page, altrimenti viene visualizzato il modulo di accesso.

SessionsController - Crea

public function create() 
{ 
    if ($this->auth->user()) return $this->redirect->to('/'); 

    return $this->view->make('sessions.login'); 
} 

Ora per il collaudo, sono nuovo di zecca ad esso. Così nudo con me ..

SessionsControllerTest

class SessionsControllerTest extends PHPUnit_Framework_TestCase { 


    public function tearDown() 
    { 
     Mockery::close(); 
    } 

    public function test_logged_in_user_cannot_see_login_page() 
    { 
     # Arrange (Create mocked versions of dependencies) 

     $user = Mockery::mock('Glenn\Repositories\User\UserRepositoryInterface'); 

     $authorizedUser = Mockery::mock('Illuminate\Auth\AuthManager'); 
     $authorizedUser->shouldReceive('user')->once()->andReturn(true); 

     $redirect = Mockery::mock('Illuminate\Routing\Redirector'); 
     $redirect->shouldReceive('to')->once()->andReturn('redirected to home'); 

     $view = Mockery::mock('Illuminate\View\Environment'); 


     # Act (Attempt to go to login page) 

     $session = new SessionsController($user, $authorizedUser, $redirect, $view); 
     $result = $session->create(); 

     # Assert (Return to home page) 
    } 
} 

Questo tutti i passaggi, ma io non voglio avere a dichiarare tutte queste dipendenze deriso per ogni test che scrivo nel mio SessionsControllerTest. C'è un modo per dichiarare queste dipendenze derise una volta nel dire un costruttore? e poi chiamarli da lì variabili per deridere?

Grazie per eventuali suggerimenti e il tempo di leggere la mia domanda.

risposta

10

È possibile utilizzare il metodo setUp per dichiarare eventuali dipendenze globali per l'intera classe di test. E 'simile al metodo tearDown che si sta utilizzando:

public function setUp() 
{ 
    // This method will automatically be called prior to any of your test cases 
    parent::setUp(); 

    $this->userMock = Mockery::mock('Glenn\Repositories\User\UserRepositoryInterface'); 
} 

Tuttavia questo sistema non funziona se il set up per le finte differisce tra i test. Per questo caso è possibile utilizzare un metodo di supporto:

protected function getAuthMock($isLoggedIn = false) 
{ 
    $authorizedUser = Mockery::mock('Illuminate\Auth\AuthManager'); 
    $authorizedUser->shouldReceive('user')->once()->andReturn($isLoggedIn); 
} 

Poi, quando è necessario l'auth deridere si può chiamare getAuthMock. Questo può semplificare molto i tuoi test.

Tuttavia

non credo che si sta testando il controller in modo corretto. Non dovresti istanziare l'oggetto controller da solo, dovresti invece utilizzare il metodo call che esiste nella classe TestCase di Laravel. Prova a dare un'occhiata a this article per testare i controller Laravel di Jeffrey Way. Penso che stai cercando di fare qualcosa di più sulla falsariga di questo test:

class SessionsControllerTest extends TestCase 
{ 
    public function setUp() 
    { 
     parent::setUp(); 
    } 

    public function tearDown() 
    { 
     Mockery::close(); 
    } 

    public function test_logged_in_user_cannot_see_login_page() 
    { 
     // This will bind any instances of the Auth manager during 
     // the next request to the mock object returned from the 
     // function below 
     App::instance('Illuminate\Auth\Manager', $this->getAuthMock(true)); 

     // Act 
     $this->call('/your/route/to/controller/method', 'GET'); 

     // Assert 
     $this->assertRedirectedTo('/'); 

    } 

    protected function getAuthMock($isLoggedIn) 
    { 
     $authMock = Mockery::mock('Illuminate\Auth\Manager'); 
     $authMock->shouldReceive('user')->once()->andReturn($isLoggedIn); 
     return $authMock; 
    } 
} 
+0

Grazie a voi @watcher! Apprezzo la tua risposta completa –

+1

np, felice di aiutare –

2

Sì, è possibile utilizzare un "helper". Sposta la creazione delle dipendenze burlate in un'altra funzione, quindi chiamala quando ne hai bisogno. Controlla la diapositiva 52 in questa presentazione: https://speakerdeck.com/jcarouth/guiding-object-oriented-design-with-tests-1 (controlla l'intera faccenda, ma l'esempio si trova sulla diapositiva 52)

Modifica: Il modo setUp è ancora migliore, stavo pensando a qualcosa che non ti serviva in TUTTO i test, ma penso che quello che hai descritto facendolo nel setUp sia molto meglio.

+0

Grazie per questo riferimento @Jessica, lo apprezzo. –

Problemi correlati