PHPUnit ожидает сбоя исключения из-за предупреждения foreach

Я хочу проверить, что метод 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

Похоже, проблема с вашим методом foo() ... Ошибка говорит вам, что проблема с foreach(). PHPUnit, вероятно, делает исключение из предупреждения, которое генерирует PHP, поэтому вы получаете это исключение, а не то, которое вы ожидаете.

ishegg 09.03.2018 17:33

ishegg В dev предупреждение также является исключением, но оно того типа, которого я ожидал. Если я настрою класс в dev так, как я это делаю в своем тесте, я получу это исключение Whoops \ Exception \ ErrorException (E_WARNING) Invalid argument supplied for foreach(). Вы знаете, как остановить PHPUnit от изменения класса исключения и выдачи исходного предупреждения / исключения?

con-- 09.03.2018 18:12

Какой код вы используете для превращения PHP Warning в ErrorException?

ishegg 09.03.2018 19:32

Я предполагаю, что Whoops на самом деле не запускается в ваших тестах, поэтому вы не получаете ErrorException, которого ожидаете ...

ishegg 09.03.2018 22:11

Правильно, я думаю, что могу решить эту проблему, отключив PHPUnit от превращения предупреждения в исключение или заключив предупреждение в собственный класс исключения. Если бы исключение было типа InvalidArguementException, это было бы хорошо, или если бы оно вообще не генерировало исключение в этот момент, это было бы хорошо, потому что позже возникнет реальное исключение из вызова функции-члена с нулевым значением из-за того, что foreach пуст. Я не уверен, что есть способ запускать крики в тестовых примерах. Я думаю, что идеально было бы использовать флаг phpunit для подавления предупреждений или чего-то еще.

con-- 09.03.2018 22:54

Это хакерство - я уверен, что есть способ получше, но попробуйте использовать set_error_handler() для выдачи ErrorException при предупреждениях (может быть, в вашем файле начальной загрузки?). Это должно разобраться.

ishegg 09.03.2018 22:57

Позвольте нам продолжить обсуждение в чате.

con-- 09.03.2018 22:58
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
8
425
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Добавление следующего в 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 за то, что указал мне в правильном направлении.

Другие вопросы по теме