我试图在Laravel 5中对我的控制器进行单元测试,但是有一些严重的问题困扰着我。如果我真的想要进行独立的单元测试,我似乎不得不用大量的短函数和静态类交换依赖注入的等价物。
首先,我在文档中看到的“单元测试”对我来说不是单元测试。这看起来更像是功能测试。我无法测试隔离的控制器函数,因为我必须遍历整个框架,如果有任何代码与我的数据库进行交互,我将需要实际地为我的数据库添加种子。
因此,反过来,我想测试与框架隔离的控制器。然而,事实证明,这是相当困难的。
让我们看一下这个示例函数(为了解决这个问题,我已经排除了这个函数的某些部分):
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类,或者重定向函数呢?我需要用依赖注入重写类/函数,如下所示:
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());
}
}最后,我得到了一个复杂的单元测试,充满了模拟:
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类注入到我的控制器中?
发布于 2015-04-08 22:42:46
你不应该尝试单元测试控制器。它们被设计成通过HTTP协议调用它们来进行功能测试。这就是控制器的设计方式,Laravel提供了许多框架断言,您可以在测试中包括这些断言,以确保它们按照预期工作。
但是,如果您想要对控制器中包含的应用程序代码进行单元测试,那么实际上应该考虑使用命令。
使用命令可以将应用程序逻辑从控制器提取到类中。然后,您可以对类/命令进行单元测试,以确保得到预期的结果。
然后,您可以简单地从控制器调用命令。
事实上,Laravel文档告诉您
我们可以将所有这些逻辑放入控制器方法中;但是,这有几个缺点.单元测试命令更加困难,因为我们还必须生成一个存根HTTP请求,并对应用程序进行完整的请求,以测试购买播客逻辑。
https://stackoverflow.com/questions/29457764
复制相似问题