2016-02-15 3 views
2

Я разрабатываю пакет Laravel, который включает в себя контроллеры, которые я хочу проверить. Проблема в том, что исключение выбрасывается внутри одного из этих контроллеров, обработчик исключений Laravel захватывает его и выводит ответ HTTP 500. PHPUnit не является мудрее, и тесты просто не соответствуют утверждению 200 OK. Отсутствие трассировки стека в выводах PHPUnit как локально, так и на таких сервисах, как Travis CI, чрезвычайно затрудняет рабочий процесс.Как я могу переопределить обработчик исключений Laravel в тестах PHPUnit?

Я знаю, что я мог бы исключить исключение из такого места, как \App\Exceptions\Handler, но поскольку это пакет, я не могу изменять эти файлы приложений (laravel/laravel - это просто зависимость для тестирования, чтобы вставлять в необходимые компоненты для тестирования контроллеров).

я бы подумал set_exception_handler() вызов ниже TestCase будет работать, но удачливый это не имеет никакого воздействия:

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

Может кто-нибудь сказать мне, почему выше не работает?

ответ

1

Unittests должен проверять отдельные устройства, а не все приложение.

Есть большие шансы, что вы выполняете функциональное или интеграционное тестирование.

Когда вы тестируете контроллеры и ожидаете ответа 200, все, что вам нужно знать, - это код ответа. 500 ответ не проходит тест, что указывает на неисправность или неправильную конфигурацию. Инструмент CI должен показывать только количество пройденных/неудачных тестов.

Тестирование не отлаживается и не должно содержать никаких специальных обратных трасс. Если вы чувствуете, что у вас недостаточно информации о характере ошибки, вы должны ознакомиться с обработкой ошибок и протоколированием. В противном случае вы столкнетесь с одной и той же проблемой с отсутствием информации, когда ошибки произойдут в производстве.

+0

Вы правы - все исключения, которые я хочу смотреть на может быть вызвано в единицах в другом месте. Я слишком много тестирую в единицах, потому что сложная задача написания сотен тестов делает меня ленивым ... – tjbp

0

Ваша попытка сбросить обработчик исключений, где вы это сделали, не будет работать (как вы уже выяснили). Когда вы используете метод call() для запроса, Laravel создает новый экземпляр ядра Http, и когда он обрабатывает новый запрос, он загружается сам и запускает загрузчик 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; 
} 
Смежные вопросы