2014-04-29 8 views
7

Po tym, jak w końcu udało mi się zdać mój głupi, prosty test, mam wrażenie, że nie robię tego poprawnie.Testy Laravel z PHPUnit i Mockery - Konfigurowanie zależności od testu kontrolera

Mam SessionsController, który jest odpowiedzialny za wyświetlanie strony logowania i logowania użytkownika w.

zdecydowałem się nie używać fasady tak, że nie będzie musiał przedłużyć laravel za TestCase i podjąć trafień wydajności na moich testach jednostkowych. W związku z tym, mam wszystkie zależności wstrzykiwany przez regulatora, jak tak -

SessionsController - Konstruktor

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

Zrobiłem niezbędne deklarowania zmiennych i używając nazw, które nie będę zawrzeć tutaj jako niepotrzebne.

Metoda create wykrywa, czy użytkownik jest uprawniony, jeśli są one wtedy przekierowuję je do strony głównej, w przeciwnym razie są wyświetlane formularz logowania.

SessionsController - Tworzenie

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

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

Teraz do testów, jestem nowy na tym. Tak goły ze mną ..

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) 
    } 
} 

To wszystko przechodzi, ale nie chcę, aby zadeklarować wszystkie te wyśmiewany zależności dla każdego testu, że piszę w moim SessionsControllerTest. Czy istnieje sposób, aby zadeklarować te wyśmiewane zależności raz, powiedzmy, konstruktora? a następnie wywoływać je tam zmienne do kpiny?

Dziękuję za wszelkie sugestie i poświęcenie czasu na przeczytanie mojego pytania.

Odpowiedz

10

Możesz użyć metody setUp, aby zadeklarować zależności globalne dla całej klasy testowej. Jest podobny do sposobu tearDown jesteś zalogowany jako:

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'); 
} 

jednak, że nie będzie działać, jeśli ustawiona na pozornie różni się między testami. W tym przypadku można użyć metody pomocnika:

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

Wtedy kiedy trzeba auth kpić można po prostu zadzwonić getAuthMock. Może to znacznie uprościć twoje testy.

Jednak

nie sądzę jesteś testowania kontrolera poprawnie. Nie powinieneś samodzielnie tworzyć instancji kontrolera, zamiast tego powinieneś używać metody call, która istnieje w klasie Laravel TestCase. Wypróbuj testowanie this article na temat testowania kontrolerów Laravel przez Jeffrey Way. Myślę, że chcesz zrobić coś więcej w tym teście:

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

Dziękuję @ watcher! Doceniam twoją dokładną odpowiedź –

+1

np., Miło mi pomóc –

2

Tak, możesz użyć "pomocnika". Przenieś tworzenie wyśmianych zależności do innej funkcji, a następnie wywołaj je, gdy ich potrzebujesz. Sprawdź slajd 52 w tej prezentacji: https://speakerdeck.com/jcarouth/guiding-object-oriented-design-with-tests-1 (dobrze sprawdzić całą sprawę, ale przykład jest na slajdzie 52)

Edytuj: Sposób ustawiania jest jeszcze lepszy, myślałem o czymś, czego nie potrzebujesz w WSZYSTKICH testy, ale myślę, że to, co opisałeś, robiąc to w setUp jest znacznie lepsze.

+0

Dziękuję za referencję @Jessica, doceniam to. –