繁体   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