Я хочу проверить, что метод foo() выдает исключение. Проблема в том, что я не могу заставить PHPUnit expectException() перехватить исключение.
foo() выглядит примерно так:
public function foo()
{
$params = $this->readAndFormatConfig();
// exception actually gets thrown in this method
$this->method->throws->exception($params);
}
Если я поймаю исключение вручную, оно будет работать нормально, например:
public function testFoo()
{
$badConfig = new Config([]);
$driver = new bar($badConfig);
$exceptionThrown = false;
try {
$driver->foo();
} catch (Exception $e) {
$exceptionThrown = true;
}
$this->assertTrue($exceptionThrown);
}
Если я поймаю это с помощью expectException, например:
public function testFoo()
{
$badConfig = new Config([]);
$driver = new bar($badConfig);
$this->expectException(Exception::class);
$driver->foo();
}
тест не проходит, и я получаю исключение:
MyTestClass::testFoo Invalid argument supplied for foreach()
Результат get_class($e) - PHPUnit_Framework_Error_Warning, что меня удивило, но объясняет, почему первый тест работает, а второй - нет.
Я бы хотел либо проигнорировать предупреждение и дождаться появления настоящего исключения, либо получить исходное предупреждение, а не PHPUnit_Framework_Error_Warning.
Я использую php 5.6.32 и PHPUnit 5.7.15
ishegg В dev предупреждение также является исключением, но оно того типа, которого я ожидал. Если я настрою класс в dev так, как я это делаю в своем тесте, я получу это исключение Whoops \ Exception \ ErrorException (E_WARNING) Invalid argument supplied for foreach(). Вы знаете, как остановить PHPUnit от изменения класса исключения и выдачи исходного предупреждения / исключения?
Какой код вы используете для превращения PHP Warning в ErrorException?
Я предполагаю, что Whoops на самом деле не запускается в ваших тестах, поэтому вы не получаете ErrorException, которого ожидаете ...
Правильно, я думаю, что могу решить эту проблему, отключив PHPUnit от превращения предупреждения в исключение или заключив предупреждение в собственный класс исключения. Если бы исключение было типа InvalidArguementException, это было бы хорошо, или если бы оно вообще не генерировало исключение в этот момент, это было бы хорошо, потому что позже возникнет реальное исключение из вызова функции-члена с нулевым значением из-за того, что foreach пуст. Я не уверен, что есть способ запускать крики в тестовых примерах. Я думаю, что идеально было бы использовать флаг phpunit для подавления предупреждений или чего-то еще.
Это хакерство - я уверен, что есть способ получше, но попробуйте использовать set_error_handler() для выдачи ErrorException при предупреждениях (может быть, в вашем файле начальной загрузки?). Это должно разобраться.
Позвольте нам продолжить обсуждение в чате.






Добавление следующего в boostrap.php преобразует предупреждения в исключения.
function warningToException($errno, $errstr, $errfile, $errline)
{
throw new Exception($errstr . " on line " . $errline . " in file " . $errfile);
}
set_error_handler("warningToException", E_WARNING);
Это позволило пройти следующий тест.
public function testFoo()
{
$badConfig = new Config([]);
$driver = new bar($badConfig);
$this->expectException(Exception::class);
$driver->foo();
}
Я думаю, что лучшим методом было бы ожидать PHPUnit_Framework_Error_Warning в тесте, как предложил Ишегг.
В итоге я убедился, что объект, который я передаю в foreach, доступен для обхода, перед тем, как войти в цикл.
public function foo()
{
if (is_array($x) || $x instanceof \Traversable) {
// do stuff
} else {
// return false;
}
}
Думаю, в этом случае имеет смысл провести рефакторинг кода приложения. Что я действительно пытаюсь проверить, так это то, что функция foo возвращает false, если приложение неправильно настроено, поэтому правильная обработка неправильной конфигурации кажется мне правильным путем.
Если вы по какой-то причине наткнулись на этот вопрос и действительно хотите преобразовать предупреждения в класс исключения, отличный от PHPUnit_Framework_Error_Warning, я сделал это именно так.
Спасибо ishegg за то, что указал мне в правильном направлении.
Похоже, проблема с вашим методом
foo()... Ошибка говорит вам, что проблема сforeach(). PHPUnit, вероятно, делает исключение из предупреждения, которое генерирует PHP, поэтому вы получаете это исключение, а не то, которое вы ожидаете.