Как выполнить код после trigger_error (…, E_USER_WARNING) в модульном тесте (PHPUnit)?

У меня такой код:

class ToBeTested { function simpleMethod($param) { if(0 === $param) { trigger_error("Param is 0!", E_USER_WARNING); return false; } return true; } } 

и проверьте этот код:

 class SimpleTest extends PHPUnit_Framework_TestCase { function testSimpleMethod() { $toBeTestedObject = new ToBeTested(); $this->assertFalse($toBeTestedObject->simpleMethod(0)); } } 

Я знаю, как тестировать, если ошибка запускается ( $this->setExpectedException() ), но я не знаю, как выполнить код после функции trigger_error() .

Помните, что в PHPUnit E_USER_WARNING не преобразуется в PHPUnit_Framework_Error_Warning (который может быть отключен), но он преобразуется в PHPUnit_Framework_Error (который нельзя отключить).

Это одно из тех мест, где вам «официально» разрешено использовать оператор @ 🙂

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

 class SimpleTest extends PHPUnit_Framework_TestCase { function testSimpleMethodReturnValue() { $toBeTestedObject = new ToBeTested(); $this->assertFalse(@$toBeTestedObject->simpleMethod(0)); } /** * @expectedException PHPUnit_Framework_Error */ function testSimpleMethodEmitsWarning() { $toBeTestedObject = new ToBeTested(); $toBeTestedObject->simpleMethod(0); } } 

Ответ заключается в том, что в PHPUnit 3.4.15 есть класс handleError методом handleError который выполняется при возникновении любой ошибки. Для ошибки, такой как E_USER_* этот метод всегда выдает PHPUnit_Framework_Error , поэтому выполнение остальной части кода останавливается.

Думаю, единственный способ предотвратить это – отключить отчеты об ошибках пользователей. Это можно сделать так:

 class SimpleTest extends PHPUnit_Framework_TestCase { function testSimpleMethod() { $toBeTestedObject = new ToBeTested(); 
// disable user errors reporting $oldReportingLevel = error_reporting(); error_reporting($oldReportingLevel ^ (E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE));
// check the condition $this->assertFalse($toBeTestedObject->simpleMethod(0));
// recover old error reporting level error_reporting($oldReportingLevel); } }

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

Итак, что-то вроде этого:

 class SimpleTest extends PHPUnit_Framework_TestCase { function testSimpleMethod() { set_error_handler(array($this, '_handleWarnedMethod'), E_USER_WARNING); $toBeTestedObject = new ToBeTested(); $this->assertFalse($toBeTestedObject->simpleMethod(0)); restore_error_handler(); } private function _handleWarnedMethod($errno, $errstr) { $this->assertEquals(E_USER_WARNING, $errno); $this->assertEquals('Param is 0!', $errstr); } } 

Как всегда, подавление ошибок – это не лучшая идея 🙂