简体   繁体   English

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

[英]Laravel testing with PHPUnit and Mockery - Setting up dependencies on Controller test

After finally getting my stupid simple test to pass, I have a feeling that I'm not doing it correctly. 在最终让我的愚蠢简单测试通过后,我感觉我没有正确地做到这一点。

I have a SessionsController, that is responsible for displaying a login page and logging a user in. 我有一个SessionsController,负责显示登录页面并记录用户。

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. 我决定不使用外墙,这样我就不必延长Laravel的TestCase并在我的单元测试中受到性能影响。 Therefore, I have injected all the dependencies through the controller, like so - 因此,我已通过控制器注入所有依赖项,如此 -

SessionsController - Constructor 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. 我已经完成了必要的变量声明和使用命名空间,我不打算将其包括在内,因为它是不必要的。

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. create方法检测用户是否被授权,如果是,则将其重定向到主页,否则显示登录表单。

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

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. 这一切都通过了,但我不想为我在SessionsControllerTest中编写的每个测试声明所有这些模拟的依赖项。 Is there a way to declare these mocked dependencies once in say a constructor? 有没有办法在构造函数中声明这些模拟的依赖项? and then call them by there variables for mocking? 然后通过变量调用它们进行模拟?

You can use the setUp method to declare any dependencies that are global for the entire test class. 您可以使用setUp方法声明整个测试类的全局依赖项。 It's similar to the tearDown method you're currently using: 它与您当前使用的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');
}

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

Then when you need the auth mock you can just call getAuthMock . 然后当你需要auth mock时,你可以调用getAuthMock This can greatly simplify your tests. 这可以大大简化您的测试。

However 然而

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. 您不应该自己实例化控制器对象,而应该使用Laravel的TestCase类中存在的call方法。 Try checking out this article about testing Laravel Controllers by Jeffrey Way. 尝试查看关于Jeffrey Way测试Laravel控制器的这篇文章 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;
    }
}

Yes, you can use a "helper". 是的,你可以使用“助手”。 Move the creation of the mocked dependencies into another function, then call that when you need them. 将模拟依赖项的创建移动到另一个函数中,然后在需要时调用它。 Check out slide 52 in this presentation: https://speakerdeck.com/jcarouth/guiding-object-oriented-design-with-tests-1 (well check out the whole thing, but the example is on slide 52) 查看此演示文稿中的幻灯片52: https//speakerdeck.com/jcarouth/guiding-object-oriented-design-with-tests-1 (查看整个内容,但示例在幻灯片52上)

Edit: The setUp way is even better, I was thinking for something you didn't need in ALL the tests, but I think for what you described doing it in the setUp is way better. 编辑:setUp方式甚至更好,我正在考虑你在所有测试中不需要的东西,但我认为你所描述的在setUp中做的更好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM