проверьте возвращаемое значение метода, который вызывает ошибку с помощью PHPUnit

StackOverflow https://stackoverflow.com/questions/1225776

Вопрос

Этот вопрос специфичен для использования PHPUnit.

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

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

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

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

Это было полезно?

Решение

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

Обработчик ошибок 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);
}

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

Ре:Комментарий: Это отличный вопрос, и я понятия не имел, пока не провел пару тестов.Похоже, что так и будет нет восстановите исходное значение по умолчанию, по крайней мере, начиная с 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;
}

Ре:Второй Комментарий:

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

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

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

Дальнейшие размышления

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

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

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

<phpunit convertErrorsToExceptions="false"
         convertNoticesToExceptions="false"
         convertWarningsToExceptions="false">
</phpunit>

Вместо того , чтобы ожидать общего "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;
}

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

На самом деле существует способ проверить как возвращаемое значение, так и выданное исключение (в этом случае ошибка, преобразованная 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');
}

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top