首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Laravel 5隔离控制器测试

Laravel 5隔离控制器测试
EN

Stack Overflow用户
提问于 2015-04-05 13:24:34
回答 1查看 1.9K关注 0票数 10

我试图在Laravel 5中对我的控制器进行单元测试,但是有一些严重的问题困扰着我。如果我真的想要进行独立的单元测试,我似乎不得不用大量的短函数和静态类交换依赖注入的等价物。

首先,我在文档中看到的“单元测试”对我来说不是单元测试。这看起来更像是功能测试。我无法测试隔离的控制器函数,因为我必须遍历整个框架,如果有任何代码与我的数据库进行交互,我将需要实际地为我的数据库添加种子。

因此,反过来,我想测试与框架隔离的控制器。然而,事实证明,这是相当困难的。

让我们看一下这个示例函数(为了解决这个问题,我已经排除了这个函数的某些部分):

代码语言:javascript
运行
复制
public function postLogin(\Illuminate\Http\Request $request)
{
    $this->validate($request, [
        'email' => 'required|email', 'password' => 'required',
    ]);

    $credentials = $request->only('email', 'password');

    if (Auth::attempt($credentials, $request->has('remember')))
    {
        return redirect()->intended($this->redirectPath());
    }
}

现在,问题出现在最后一行。当然,我可以模拟发送到函数的请求实例,这是没有问题的。但是我要怎么嘲笑Auth类,或者重定向函数呢?我需要用依赖注入重写类/函数,如下所示:

代码语言:javascript
运行
复制
private $auth;
private $redirector;

public function __construct(Guard $auth, \Illuminate\Routing\Redirector $redirector) 
{
    $this->auth = $auth;
    $this->redirector = $redirector;
}

public function postLogin(\Illuminate\Http\Request $request)
{
    $this->validate($request, [
        'email' => 'required|email', 'password' => 'required',
    ]);

    $credentials = $request->only('email', 'password');

    if ($this->auth->attempt($credentials, $request->has('remember')))
    {
        return $this->redirector->intended($this->redirectPath());
    }
}

最后,我得到了一个复杂的单元测试,充满了模拟:

代码语言:javascript
运行
复制
public function testPostLoginWithCorrectCredentials()
{
    $guardMock = \Mockery::mock('\Illuminate\Contracts\Auth\Guard', function($mock){
        $mock->shouldReceive('attempt')->with(['email' => 'test', 'password' => 'test'], false)->andReturn(true);
    });

    $redirectorMock = \Mockery::mock('\Illuminate\Routing\Redirector', function($mock){
        $mock->shouldReceive('intended')->andReturn('/somePath');
    });

    $requestMock = \Mockery::mock('\Illuminate\Http\Request', function($mock){
        $mock->shouldReceive('only')->with('email', 'password')->andReturn(['email' => 'test', 'password' => 'test']);
        $mock->shouldReceive('has')->with('remember')->andReturn(false);
    });

    $object = new AuthController($guardMock, $redirectorMock);
    $this->assertEquals('/somePath', $object->postLogin($requestMock));
}

现在,如果我有任何更复杂的逻辑,例如,使用一个模型,我也必须依赖注入它,并在我的类中模拟它。

在我看来,拉拉维尔似乎没有提供我想要它做的事情,或者我的测试逻辑有缺陷。是否有任何方法可以测试我的控制器功能而不失去控制的测试功能和/或必须将标准的Laravel类注入到我的控制器中?

EN

Stack Overflow用户

发布于 2015-04-08 22:42:46

你不应该尝试单元测试控制器。它们被设计成通过HTTP协议调用它们来进行功能测试。这就是控制器的设计方式,Laravel提供了许多框架断言,您可以在测试中包括这些断言,以确保它们按照预期工作。

但是,如果您想要对控制器中包含的应用程序代码进行单元测试,那么实际上应该考虑使用命令

使用命令可以将应用程序逻辑从控制器提取到类中。然后,您可以对类/命令进行单元测试,以确保得到预期的结果。

然后,您可以简单地从控制器调用命令。

事实上,Laravel文档告诉您

我们可以将所有这些逻辑放入控制器方法中;但是,这有几个缺点.单元测试命令更加困难,因为我们还必须生成一个存根HTTP请求,并对应用程序进行完整的请求,以测试购买播客逻辑。

票数 10
EN
查看全部 1 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29457764

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档