簡體   English   中英

使用PHPUnit和Mockery進行Laravel測試 - 設置Controller測試的依賴性

[英]Laravel testing with PHPUnit and Mockery - Setting up dependencies on 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;
}

我已經完成了必要的變量聲明和使用命名空間,我不打算將其包括在內,因為它是不必要的。

create方法檢測用戶是否被授權,如果是,則將其重定向到主頁,否則顯示登錄表單。

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中編寫的每個測試聲明所有這些模擬的依賴項。 有沒有辦法在構造函數中聲明這些模擬的依賴項? 然后通過變量調用它們進行模擬?

您可以使用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');
}

但是,如果您的模擬設置在測試之間有所不同,那么這將不起作用。 對於這種情況,您可以使用輔助方法:

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

然后當你需要auth mock時,你可以調用getAuthMock 這可以大大簡化您的測試。

然而

我認為你沒有正確測試你的控制器。 您不應該自己實例化控制器對象,而應該使用Laravel的TestCase類中存在的call方法。 嘗試查看關於Jeffrey Way測試Laravel控制器的這篇文章 我認為你希望在你的測試中做更多的事情:

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

是的,你可以使用“助手”。 將模擬依賴項的創建移動到另一個函數中,然后在需要時調用它。 查看此演示文稿中的幻燈片52: https//speakerdeck.com/jcarouth/guiding-object-oriented-design-with-tests-1 (查看整個內容,但示例在幻燈片52上)

編輯:setUp方式甚至更好,我正在考慮你在所有測試中不需要的東西,但我認為你所描述的在setUp中做的更好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM