php - 使用 PHPUnit 和 Mockery 进行 Laravel 测试 - 设置对 Controller 测试的依赖

标签 php unit-testing laravel dependency-injection laravel-4

在我的愚蠢的简单测试终于通过之后,我觉得我没有做对。

我有一个 SessionsController,它负责显示登录页面并让用户登录。

我决定不使用外观,这样我就不必扩展 Laravel 的 TestCase 并在我的单元测试中受到性能影响。因此,我通过 Controller 注入(inject)了所有依赖项,就像这样 -

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

现在开始测试,我是新手,所以请多多包涵。

session Controller 测试

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。这可以大大简化您的测试。

但是

我认为您没有正确测试您的 Controller 。您不应该自己实例化 Controller 对象,而应该使用 Laravel 的 TestCase 类中存在的 call 方法。尝试查看 Jeffrey Way 关于测试 Laravel Controller 的 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;
    }
}

关于php - 使用 PHPUnit 和 Mockery 进行 Laravel 测试 - 设置对 Controller 测试的依赖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23374247/

相关文章:

php - 被连接覆盖的 ID 列

linux - 在 linux apache php 上访问我的网站时突然出现 505 错误

php - SQLSTATE[42000] : Syntax error or access violation: 1055

php - 找不到 Laravel 5 函数 ()

python - 使用 Selenium/Python/Nose 时浏览器实例化两次

PHP - mysqldump 不起作用

python - 如何模拟对 __next__ 的调用

asp.net - 测试: I *want* to test web.配置

php - 更新 array() 中的值

php - 将 NodeJS Realtime 与现有 PHP 应用程序集成