【问题标题】:Laravel testing with PHPUnit and Mockery - Setting up dependencies on Controller test使用 PHPUnit 和 Mockery 进行 Laravel 测试 - 设置对控制器测试的依赖项
【发布时间】:2014-06-15 22:57:48
【问题描述】:

在终于通过我愚蠢的简单测试后,我有一种感觉,我做的不对。

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

【问题讨论】:

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


    【解决方案1】:

    您可以使用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 方法。尝试查看 this article 关于 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;
        }
    }
    

    【讨论】:

    • 谢谢@watcher!感谢您的详尽回答
    【解决方案2】:

    是的,您可以使用“助手”。将模拟依赖项的创建移到另一个函数中,然后在需要时调用它们。查看此演示文稿中的幻灯片 52:https://speakerdeck.com/jcarouth/guiding-object-oriented-design-with-tests-1(请查看整个内容,但示例在幻灯片 52 上)

    编辑:setUp 方式更好,我想的是你在所有测试中都不需要的东西,但我认为你在 setUp 中描述的做法更好。

    【讨论】:

    • 感谢您提供此参考@Jessica,我很感激。
    猜你喜欢
    • 2016-02-06
    • 2015-06-15
    • 2014-03-21
    • 2016-04-25
    • 2016-06-04
    • 2014-03-15
    • 2015-01-27
    • 1970-01-01
    • 2016-01-14
    相关资源
    最近更新 更多