Я работаю с внутренней структурой, в которой каждое исключение перехватывается обработчиком ошибок и возвращается в правильном ответе об ошибке JSON, подходящем для RESTFul API.
Затем у меня есть набор тестов, которые являются тестами API, которые в основном проверяют, что API возвращает правильные ответы JSON с ожидаемыми кодами ошибок.
Для каждого теста глобальные переменные модифицируются (а затем восстанавливаются) для эмуляции другого HTTP-запроса. Я делаю это таким образом, чтобы избежать перегрузки при выполнении тестов cURL (через Guzzle или аналогичные) и вызвать в среде CLI, код не знает URL-адрес сервера.
<?php
// ... example, part of a base ApiTestCase class:
// Override globals (should be backed up by PHPUnit)
$_SERVER['REQUEST_METHOD'] = $request->method;
$_SERVER['QUERY_STRING'] = http_build_query($request->parameters);
$_SERVER['PATH_INFO'] = $request->path;
$_SERVER['REQUEST_URI'] = $request->path . ($_SERVER['QUERY_STRING'] ? '?' : '') . $_SERVER['QUERY_STRING'];
$_SERVER['REQUEST_TIME'] = time();
$_SERVER['REQUEST_TIME_FLOAT'] = microtime(true);
$_SERVER['HTTP_COOKIE'] = '';
// Set headers, cookies and parameters
foreach ($request->headers as $k => $v) {
$_SERVER['HTTP_' . strtoupper(str_replace('-', '_', trim($k)))] = $v;
}
if ($_SERVER['HTTP_COOKIE']) {
$GLOBALS['_COOKIE'] = http_parse_cookie($_SERVER['HTTP_COOKIE']);
} else {
$GLOBALS['_COOKIE'] = [];
}
$GLOBALS['_REQUEST'] = $request->parameters;
$responseBody = $app->start();
$response->httpCode = http_response_code();
$response->body = $responseBody ? @json_decode($responseBody) : null;
$response->headers = headers_list();
(Я знаю, что изменение глобальных переменных таким образом нехорошо, и среда не должна напрямую полагаться на глобальные переменные, но мне все еще приходится иметь дело с устаревшим кодом.)
Затем возникает проблема: когда я пытаюсь проверить ответы об ошибках JSON: PHPUnit перехватывает выброшенное исключение (до того обработчика, о котором я упоминал в начале), поэтому у фреймворка нет шансов преобразовать его в JSON и вернуть правильный ответ.
Я попытался найти что-то в руководстве PHPUnit, чтобы отключить обработчик ошибок PHPUnit, но безуспешно.
Что я мог сделать в этом случае? Спасибо
Просто чтобы прояснить, звучит так, будто мы на самом деле не говорим о ловле исключений здесь; мы говорим об использовании PHP set_error_handler()
перехватить фатальную ошибку до ее завершения. Это будет иметь дело как с ошибками, так и с необработанными исключениями.
Одна вещь, которую вы не сможете сделать, — позволить этим ошибкам и исключениям перейти к вашей функции обработчика ошибок — как вы уже узнали, phpUnit выполняет свою собственную обработку ошибок, которую вы не можете переопределить (потому что это своего рода фундаментальный как работает phpUnit).
Вам нужно будет сказать phpUnit, какое исключение или ошибку вы ожидаете; Ваш тест будет пройден или не пройден в зависимости от того, произошла ли ошибка. Вы не будете запускать обработчик ошибок, но по правде говоря, вам это не нужно; Вы можете проверить функцию отдельно, если вам нужно. В случае ошибок вам не нужно видеть, что обработчик ошибок каждый раз выдает правильные выходные данные, просто возникает ошибка, которая запускает обработчик.
Для обычных исключений PHP вы можете использовать phpUnit’s @expectedException
аннотация над вашей тестовой функцией, например:
/**
* @expectedException YourExpectedExceptionClass
*/
function testThisWillThrowAnException() {
....
}
Если ожидается, что код PHP вызовет ошибку PHP (т. Е. Ошибку, а не исключение), вы должны использовать ту же идею, но phpUnit предоставляет вспомогательное имя класса для ошибки: PHPUnit_Framework_Error
, Итак, ваш код будет выглядеть так:
/**
* @expectedException PHPUnit_Framework_Error
*/
function testThisWillProduceAPHPError() {
....
}
В любом случае ваш тест пройдет, если произойдет ожидаемая ошибка / исключение.
Вы также можете проверить конкретные сообщения об исключениях и коды, если сам класс исключений не обладает достаточной информацией, чтобы вы знали, выполнил ли тест то, что вы хотите. Увидеть страница руководства phpUnit для аннотаций для получения дополнительной информации.
Вышеприведенный пример также верен, мой только предоставляет Исключения в качестве утверждений и дает вам знания об Исключительных работах.
/**
* @dataProvider fixturesProvider // its just example
*/
public function testDataIsWrong($fixtures)
{
try
{
//Some Code
$this->fail('Exception');
}
catch(Exception $ex)
{
$this->assertEquals($ex,'Exception');
}
}
Это также предоставляет в вашем коде возможность того, что вы можете проверить ложные или не правильные данные и утверждать, что они неверны.
Единственное реализованное мной решение, которое решает мою проблему, состоит в том, чтобы не делегировать обработчику исключительных ситуаций ответственность за создание и отправку ответов об ошибках API, а перехватывать исключения на верхнем уровне вашего приложения.
В улове у меня есть преобразователь исключения в ответ на ошибку, который позаботится об этом (или перезапустит исключение, когда это удобно), поэтому ошибки, которые не являются критическими (например, те, которые генерируют ответы HTTP 4xx), не появляются в тестах PHPUnit больше.
Мои тесты PHPUnit теперь также могут работать с объектами HTTP Response PSR-7 вместо захвата выходного буфера.