Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/263.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用PHPUnit和Mockery的Laravel测试-设置控制器测试的依赖项_Php_Unit Testing_Laravel_Dependency Injection_Laravel 4 - Fatal编程技术网

使用PHPUnit和Mockery的Laravel测试-设置控制器测试的依赖项

使用PHPUnit和Mockery的Laravel测试-设置控制器测试的依赖项,php,unit-testing,laravel,dependency-injection,laravel-4,Php,Unit Testing,Laravel,Dependency Injection,Laravel 4,在我终于通过了愚蠢的简单测试之后,我有一种感觉,我做得不对 我有一个SessionController,负责显示登录页面并让用户登录 我决定不使用facades,这样我就不必扩展Laravel的测试用例,也不必在我的单元测试中受到性能的影响。因此,我通过控制器注入了所有依赖项,如下所示- 会话控制器-构造函数 public function __construct(UserRepositoryInterface $user, AuthMa

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

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

我决定不使用facades,这样我就不必扩展Laravel的测试用例,也不必在我的单元测试中受到性能的影响。因此,我通过控制器注入了所有依赖项,如下所示-

会话控制器-构造函数

public function __construct(UserRepositoryInterface $user, 
                            AuthManager $auth, 
                            Redirector $redirect,
                            Environment $view )
{
    $this->user = $user;
    $this->auth = $auth;
    $this->redirect = $redirect; 
    $this->view = $view;
}
我已经完成了必要的变量声明并使用了名称空间,我不打算在这里将其作为不必要的内容

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

会话控制器-创建

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

    return $this->view->make('sessions.login');
}
现在,对于测试,我是全新的,所以请容忍我

会话控制器测试

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) 
    }
}
这一切都通过了,但我不想为我在SessionControllerTest中编写的每个测试声明所有这些模拟依赖项。有没有办法在构造函数中一次性声明这些模拟依赖项?然后通过这些变量调用它们进行模拟

是的,您可以使用“助手”。将模拟依赖项的创建移动到另一个函数中,然后在需要时调用该函数。查看本演示中的第52张幻灯片:(我们可以查看整个内容,但示例在第52张幻灯片上)


编辑:设置方式更好,我在考虑一些在所有测试中都不需要的东西,但我认为对于您在设置中描述的内容,这样做会更好。

您可以使用
设置
方法声明整个测试类的全局依赖项。它类似于您当前使用的
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;
    }
}

谢谢@watcher!谢谢你的详尽回答谢谢你的推荐@Jessica,我很感激。