2014-04-29 132 views
7

終於讓我愚蠢的簡單測試通過後,我感覺我沒有正確地做到這一點。Laravel使用PHPUnit和Mockery進行測試 - 在Controller上設置依賴關係test

我有一個SessionsController,這是負責顯示登錄頁面和登錄的用戶。

我已經決定不使用外牆,這樣我就不必延長Laravel的TestCase和採取的性能損失在我的單元測試中。因此,我通過控制器注入所有的依賴,就像這樣 -

SessionsController - 構造

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

我已經做了必要的變量聲明和使用的命名空間,這我不會在這裏包括它不必要的。

創建方法檢測用戶是否被授權,如果他們然後我將他們重定向到主頁,否則會顯示登錄表單。

SessionsController - 創建

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

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

現在的測試,我是全新的,以它。因此,與我裸...

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

這一切都通過,但我不希望有聲明所有爲我在寫SessionsControllerTest每個測試這些嘲笑依賴。有沒有辦法在構造函數中聲明這些模仿的依賴關係?然後通過變量調用它們來模擬?

謝謝你的任何建議,並花時間來閱讀我的問題。

回答

10

您可以使用setUp方法聲明對整個測試類都是全局的任何依賴項。它類似於您目前使用的方法tearDown

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

但是,不會,如果你的設置爲測試之間的模擬不同的工作。當你需要在auth嘲笑,你可以叫getAuthMock

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

那麼:對於這種情況,你可以使用一個輔助方法。這可以大大簡化您的測試。

然而

我不認爲你是正確的測試控制器。您不應該自己實例化控制器對象,而應該使用Laravel的TestCase類中存在的call方法。嘗試檢查出關於由Jeffrey Way測試Laravel控制器的this article。我認爲你正在考慮在你的測試中做更多的事情:

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

謝謝@watcher!我很感謝你的全面回答 –

+1

np,很高興提供幫助 –

2

是的,你可以使用「幫手」。將模擬的依賴關係創建爲另一個函數,然後在需要時調用它。查看幻燈片52在這個演示文稿中:https://speakerdeck.com/jcarouth/guiding-object-oriented-design-with-tests-1(以及檢查整個事情,但例子是在幻燈片52)

編輯:setUp的方式更好,我想的東西,你不需要在所有測試,但我認爲你所描述的在setUp中做的更好。

+0

謝謝你參考@Jessica,我很感激。 –

相關問題