如何覆盖Laravel';PHPUnit测试中的异常处理程序?
我正在开发一个包含控制器的Laravel包,我希望对其进行单元测试。问题是,如果在其中一个控制器内引发异常,Laravel的异常处理程序将捕获该异常并输出500 HTTP响应。PHPUnit并不明智,测试根本无法满足200ok断言。PHPUnit在本地和Travis CI等服务上的输出都缺少堆栈跟踪,这极大地阻碍了工作流 我知道我可以从如何覆盖Laravel';PHPUnit测试中的异常处理程序?,php,unit-testing,laravel,exception-handling,phpunit,Php,Unit Testing,Laravel,Exception Handling,Phpunit,我正在开发一个包含控制器的Laravel包,我希望对其进行单元测试。问题是,如果在其中一个控制器内引发异常,Laravel的异常处理程序将捕获该异常并输出500 HTTP响应。PHPUnit并不明智,测试根本无法满足200ok断言。PHPUnit在本地和Travis CI等服务上的输出都缺少堆栈跟踪,这极大地阻碍了工作流 我知道我可以从\App\Exceptions\Handler之类的地方重新抛出异常,但由于这是一个包,我无法修改这些应用程序文件(laravel/laravel只是测试的一个依
\App\Exceptions\Handler
之类的地方重新抛出异常,但由于这是一个包,我无法修改这些应用程序文件(laravel/laravel
只是测试的一个依赖项,以便为测试控制器引入必要的组件)
我本以为下面在TestCase
中调用set\u exception\u handler()
会起作用,但奇怪的是,它没有任何影响:
public function createApplication()
{
$app = require __DIR__.'/../bootstrap/app.php';
$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
set_exception_handler(function ($e) {
throw $e;
});
return $app;
}
有人能告诉我为什么上面的方法不起作用吗?单元测试应该测试单个单元,而不是整个应用程序 您很有可能正在进行功能或集成测试 当您测试控制器时,预计会有200个响应,您需要知道的一切就是响应代码。500响应未通过测试,表明存在故障或配置错误。CI工具应仅显示通过/失败测试的数量
测试不是调试,不应提供任何特殊的回溯。若您觉得并没有足够的关于错误性质的信息,那个么应该检查错误处理和日志记录。否则,当生产中发生错误时,您将面临同样的问题,即缺少信息 您尝试在您尝试重置异常处理程序的地方重置异常处理程序将不起作用(正如您已经发现的那样)。当您使用
call()
方法发出请求时,Laravel会生成Http内核的一个新实例,当它处理新请求时,它会自动引导并运行HandleExceptions
bootstrapper,这当然会再次重置异常处理程序
您可能无权修改\App\Exceptions\Handler
类,但不需要修改。您只需创建自己的异常处理程序,然后更新IoC容器中的绑定以使用您的异常处理程序,而不是Laravel应用程序提供的异常处理程序
因此,首先,创建新的异常处理程序:
<?php
class MyExceptionHandler extends \App\Exceptions\Handler
{
public function render($request, \Exception $e)
{
// You may want to keep all these cases for special exceptions.
// If not, just get rid of these lines.
$e = $this->prepareException($e);
if ($e instanceof HttpResponseException) {
return $e->getResponse();
} elseif ($e instanceof AuthenticationException) {
return $this->unauthenticated($request, $e);
} elseif ($e instanceof ValidationException) {
return $this->convertValidationExceptionToResponse($e, $request);
}
// Not a special exception. Just re-throw it to get meaningful output.
throw $e;
}
}
你说得对-我想看的所有异常都可以在其他单位中触发。我在单元中测试太多了,因为编写数百个测试的艰巨任务让我变得懒惰。。。
public function createApplication()
{
$app = require __DIR__.'/../bootstrap/app.php';
// Tell the tests to use your exception handler.
$app->singleton(\Illuminate\Contracts\Debug\ExceptionHandler::class, MyExceptionHandler::class);
$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
return $app;
}