2009-08-04 6 views
11

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

PHPUnit автоматически преобразует ошибки 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); 
} 

Любые идеи, как я могу этого достичь?

ответ

21

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

Обработчик ошибок 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
  • Else, используйте PHPUnit_Framework_Error как класс исключений.

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

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

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

+0

Спасибо, Джейсон. Вы случайно не знаете, автоматически ли возвращается значение PHPUnit_Framework_Error_Warning :: $, которое было проверено между тестами? Или вам нужно вручную изменить его на исходное значение? – dellsala

+0

Примечание о этот ответ. Хотя он работает с ошибками, создаваемыми встроенными функциями и методами php, он, похоже, не работает для генерируемых пользователем типов ошибок (E_USER_WARNING и E_USER_NOTICE) trigger_error. Похоже, PHPUnit не поддерживает их переключение во время выполнения (версия 3.3.17) – dellsala

3

А вместо того, чтобы ожидать общего значения "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); 
} 

Для получения дополнительной информации см Testing PHP Errors
Особенно, это говорит (цитирую) :

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

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

+0

Это не то, о чем он просил. – jason

+0

Ясон прав - не совсем то, что я просил, но хороший совет о проверке конкретного типа ошибки php с использованием типов исключений PHPUnit. – dellsala

+0

@jason: oh, ваше право :-(извините :-(Хороший ответ, кстати (вещь об использовании двух отдельных тестов, безусловно, хорошая точка) @dellsala: thanks :-) –

8

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

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

@lonut - Я искал _this_ ! 2-летняя почта, все еще актуальная. – stefgosselin

1

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

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

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

 Смежные вопросы

  • Нет связанных вопросов^_^