проверить возвращаемое значение метода, который вызывает ошибку с PHPUnit - PullRequest
11 голосов
/ 04 августа 2009

Этот вопрос относится только к использованию PHPUnit.

PHPUnit автоматически преобразует ошибки php в исключения. Есть ли способ проверить возвращаемое значение метода, который вызывает ошибку php (встроенные или сгенерированные пользователем ошибки через trigger_error )?

Пример кода для тестирования:

function load_file ($file)
{
    if (! file_exists($file)) {
        trigger_error("file {$file} does not exist", E_USER_WARNING);
        return false;
    }
    return file_get_contents($file);
}

Это тип теста, который я хочу написать:

public function testLoadFile ()
{
    $this->assertFalse(load_file('/some/non-existent/file'));
}

Проблема, с которой я столкнулся, заключается в том, что вызванная ошибка приводит к сбою моего модульного теста (как и должно быть). Но если я пытаюсь его перехватить или установить ожидаемое исключение, любой код, который после возникновения ошибки не будет выполнен, не сможет проверить возвращаемое значение метода.

Этот пример не работает:

public function testLoadFile ()
{
    $this->setExpectedException('Exception');
    $result = load_file('/some/non-existent/file');

    // code after this point never gets executed

    $this->assertFalse($result);
}

Есть идеи, как мне этого добиться?

Ответы [ 4 ]

21 голосов
/ 04 августа 2009

Нет способа сделать это за один юнит-тест. Это возможно, если вы разбиваете тестирование возвращаемого значения и уведомления на два разных теста.

Обработчик ошибок PHPUnit отлавливает ошибки PHP и замечает их и преобразует в исключения, что по определению останавливает выполнение программы. Функция, которую вы тестируете, никогда не возвращается вообще. Однако вы можете временно отключить преобразование ошибок в исключения даже во время выполнения.

Это, вероятно, проще с примером, поэтому вот как должны выглядеть два теста:

public function testLoadFileTriggersErrorWhenFileNotFound()
{
    $this->setExpectedException('PHPUnit_Framework_Error_Warning'); // Or whichever exception it is
    $result = load_file('/some/non-existent/file');

}

public function testLoadFileRetunsFalseWhenFileNotFound()
{
    PHPUnit_Framework_Error_Warning::$enabled = FALSE;
    $result = load_file('/some/non-existent/file');

    $this->assertFalse($result);
}

Это также имеет дополнительный бонус, который делает ваши тесты более четкими, чистыми и самодокументирующими.

Re: Комментарий: Это отличный вопрос, и я понятия не имел, пока не провел пару тестов. Похоже, что не восстановит значение по умолчанию / оригинал, по крайней мере, начиная с PHPUnit 3.3.17 (текущий стабильный выпуск прямо сейчас).

Итак, я бы на самом деле изменил вышесказанное, чтобы оно выглядело так:

public function testLoadFileRetunsFalseWhenFileNotFound()
{
    $warningEnabledOrig = PHPUnit_Framework_Error_Warning::$enabled;
    PHPUnit_Framework_Error_Warning::$enabled = false;

    $result = load_file('/some/non-existent/file');

    $this->assertFalse($result);

    PHPUnit_Framework_Error_Warning::$enabled = $warningEnabledOrig;
}

Re: Второй комментарий:

Это не совсем так. Я смотрю на обработчик ошибок PHPUnit, и он работает следующим образом:

  • Если это E_WARNING, используйте PHPUnit_Framework_Error_Warning в качестве класса исключения.
  • Если это ошибка E_NOTICE или E_STRICT, используйте PHPUnit_Framework_Error_Notice
  • Иначе, используйте PHPUnit_Framework_Error в качестве класса исключения.

Итак, да, ошибки E_USER_* не превращаются в класс * _Warning или * _Notice PHPUnit, они по-прежнему преобразуются в общее исключение PHPUnit_Framework_Error.

Дальнейшие мысли

Хотя это зависит именно от того, как используется функция, я, вероятно, переключился бы на выдачу действительного исключения вместо вызова ошибки, если бы это был я. Да, это изменило бы логический поток метода и код, который использует метод ... прямо сейчас выполнение не останавливается, когда он не может прочитать файл. Но вам решать, действительно ли запрошенный файл не существует исключительное поведение. Я склонен использовать исключения гораздо чаще, чем ошибки / предупреждения / уведомления, потому что они легче обрабатываются, тестируются и работают в потоке ваших приложений. Я обычно резервирую уведомления для таких вещей, как устаревшие вызовы методов и т. Д.

9 голосов
/ 04 августа 2009

Используйте файл конфигурации phpunit.xml и отключите уведомление / предупреждение / ошибку к преобразованию исключения. Подробнее подробности в руководстве . Это в основном что-то вроде этого:

<phpunit convertErrorsToExceptions="false"
         convertNoticesToExceptions="false"
         convertWarningsToExceptions="false">
</phpunit>
3 голосов
/ 04 августа 2009

Вместо ожидания "Exception", как насчет ожидания "PHPUnit_Framework_Error"?

Что-то вроде этого может сделать:

/**
 * @expectedException PHPUnit_Framework_Error
 */
public function testFailingInclude()
{
    include 'not_existing_file.php';
}

Который, я полагаю, мог бы быть записан как:

public function testLoadFile ()
{
    $this->setExpectedException('PHPUnit_Framework_Error');
    $result = load_file('/some/non-existent/file');

    // code after this point never gets executed

    $this->assertFalse($result);
}

Для получения дополнительной информации см. Проверка ошибок PHP
Особенно говорится (цитируя):

PHPUnit_Framework_Error_Notice и PHPUnit_Framework_Error_Warning представляют PHP уведомления и предупреждения, соответственно.


Глядя на файл /usr/share/php/PHPUnit/TextUI/TestRunner.php, который есть в моей системе, я вижу этот (строка 198 и далее) :

if (!$arguments['convertNoticesToExceptions']) {
    PHPUnit_Framework_Error_Notice::$enabled = FALSE;
}

if (!$arguments['convertWarningsToExceptions']) {
    PHPUnit_Framework_Error_Warning::$enabled = FALSE;
}

Так, может, вам придется передать какой-то параметр, чтобы активировать это поведение? Но, похоже, он включен по умолчанию ...

1 голос
/ 04 декабря 2013

На самом деле существует способ проверить как возвращаемое значение, так и выданное исключение (в этом случае ошибка, преобразованная PHPUnit).

Вам просто нужно сделать следующее:

public function testLoadFileTriggersErrorWhenFileNotFound()
{
    $this->assertFalse(@load_file('/some/non-existent/file'));

    $this->setExpectedException('PHPUnit_Framework_Error_Warning'); // Or whichever exception it is
    load_file('/some/non-existent/file');
}

Обратите внимание, что для проверки возвращаемого значения необходимо использовать оператор подавления ошибок при вызове функции (@ перед именем функции). Таким образом, исключение не будет выдано, и выполнение будет продолжено. Затем вы должны установить ожидаемое исключение как обычно, чтобы проверить ошибку.

То, что вы не можете сделать, это протестировать несколько исключений в модульном тесте.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...