使用PHPUnit和Mockery进行Laravel测试-设置对Controller测试的依赖 [英] Laravel testing with PHPUnit and Mockery - Setting up dependencies on Controller test

查看:211
本文介绍了使用PHPUnit和Mockery进行Laravel测试-设置对Controller测试的依赖的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

终于让我愚蠢的简单测试通过了,我有一种感觉,就是我做得不好.

After finally getting my stupid simple test to pass, I have a feeling that I'm not doing it correctly.

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

I have a SessionsController, that is responsible for displaying a login page and logging a user in.

我决定不使用外观,这样我就不必扩展Laravel的TestCase并在单元测试中获得性能上的提升.因此,我已经通过控制器注入了所有依赖项,就像这样-

I have decided not to use facades so that I wouldn't have to extend Laravel's TestCase and take a performance hit on my unit tests. Therefore, I have injected all the dependencies through the controller, like so -

SessionsController -构造函数

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

我已经完成了必要的变量声明和使用名称空间的工作,在此不再赘述.

I have done the necessary declaring of variables and using the namespaces, which I'm not going to include here as its unnecessary.

create方法检测用户是否被授权,如果他们被授权,那么我会将其重定向到主页,否则将显示登录表单.

the create method detects if a user is authorized, if they are then I redirect them to the home page, otherwise they are displayed the login form.

SessionsController -创建

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

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

现在要进行测试,我是第一次接触它,所以请耐心等待.

Now for the testing, I'm brand new to it, so bear with me.

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中编写的每个测试都声明所有这些模拟的依赖项.有没有办法一次说一个构造函数来声明这些模拟的依赖项?然后通过那里的变量来调用它们以进行模拟?

This all passes, but I don't want to have to declare all of these mocked dependencies for each test that I write in my SessionsControllerTest. Is there a way to declare these mocked dependencies once in say a constructor? and then call them by there variables for mocking?

推荐答案

您可以使用setUp方法声明整个测试类的全局依赖项.它类似于您当前正在使用的tearDown方法:

You can use the setUp method to declare any dependencies that are global for the entire test class. It's similar to the tearDown method you're currently using:

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

但是,如果您的模拟设置在两次测试之间不同,那将无法正常工作.对于这种情况,您可以使用辅助方法:

However that won't work if your set up for the mock differs between tests. For this case you can use a helper method:

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

然后,当您需要身份验证模拟时,只需调用getAuthMock.这样可以大大简化您的测试.

Then when you need the auth mock you can just call getAuthMock. This can greatly simplify your tests.

但是

我认为您没有正确测试控制器.您不应该自己实例化控制器对象,而应该利用Laravel TestCase类中存在的call方法.尝试查看本文关于测试Jeffrey Way的Laravel控制器的文章.我认为您正在尝试在测试中做更多的事情:

I don't think you're testing your controller correctly. You shouldn't instantiate the controller object yourself, instead you should utilize the call method which exists in Laravel's TestCase class. Try checking out this article about testing Laravel Controllers by Jeffrey Way. I think you're looking to do something more along the lines of this in your test:

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

这篇关于使用PHPUnit和Mockery进行Laravel测试-设置对Controller测试的依赖的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆