【问题标题】:How can I override Laravel's exception handler in PHPUnit tests?如何在 PHPUnit 测试中覆盖 Laravel 的异常处理程序?
【发布时间】:2016-05-26 23:51:44
【问题描述】:

我正在开发一个包含控制器的 Laravel 包,我希望对其进行单元测试。问题是如果在这些控制器之一中抛出异常,Laravel 的异常处理程序会捕获它并输出 500 HTTP 响应。 PHPUnit 并不明智,测试根本无法满足 200 OK 断言。 PHPUnit 在本地和 Travis CI 等服务的输出中缺少堆栈跟踪极大地阻碍了工作流程。

我知道我可以从 \App\Exceptions\Handler 等某个地方重新抛出异常,但由于这是一个包,我无法修改这些应用程序文件(laravel/laravel 只是测试的依赖项,以便绳索在必要的组件中测试控制器)。

我原以为TestCase 中的set_exception_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;
}

谁能告诉我为什么上面的方法不起作用?

【问题讨论】:

    标签: php unit-testing laravel exception-handling phpunit


    【解决方案1】:

    单元测试应该测试单个单元,而不是整个应用程序。

    您很有可能正在进行功能或集成测试。

    当您测试控制器并期望得到 200 个响应时,您需要知道的只是响应代码。 500 响应未通过测试,这表明故障或配置错误。 CI 工具应该只显示通过/失败测试的数量。

    测试不是调试,不应提供任何特殊的回溯。如果你觉得你没有足够的关于错误性质的信息,你应该检查你的错误处理和日志记录。否则,当生产中发生错误时,您将面临同样的信息缺失问题。

    【讨论】:

    • 你是对的 - 我想查看的所有异常都可以在其他地方以单位触发。我的单元测试太多了,因为编写数百个测试的艰巨任务让我很懒惰......
    【解决方案2】:

    您尝试重置您所做的异常处理程序将不起作用(正如您已经发现的那样)。当你使用call() 方法发出请求时,Laravel 会创建一个新的 Http Kernel 实例,当它处理新请求时,它会自行引导并运行 HandleExceptions 引导程序,这当然会再次重置异常处理程序.

    您可能无权修改\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;
        }
    }
    

    现在,在您的 createApplication() 方法中,更新异常处理程序绑定:

    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;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-18
      • 2021-09-17
      • 2012-08-07
      • 1970-01-01
      • 2018-12-29
      • 2022-08-18
      • 2019-08-07
      • 2020-01-23
      相关资源
      最近更新 更多