Обработка ошибок
Запускающий тест PHPUnit регистрирует обработчик ошибок обработчик ошибок и обрабатывает E_DEPRECATED, E_USER_DEPRECATED, E_NOTICE, E_USER_NOTICE, E_STRICT, E_WARNING и E_USER_WARNING ошибки. Мы будем использовать термин «проблемы» для обозначения E_DEPRECATED, E_USER_DEPRECATED, E_NOTICE, E_USER_NOTICE, E_STRICT, E_WARNING и E_USER_WARNING ошибок в остальной части этой главы.
Обработчик ошибок активен только во время выполнения теста и обрабатывает только проблемы, вызванные кодом теста или кодом, вызываемым из кода теста. Он игнорирует проблемы, вызванные собственным кодом PHPUnit, а также кодом зависимостей PHPUnit.
Другие обработчики ошибок
Когда запускающий тест PHPUnit обнаруживает (после вызова set_error_handler() для регистрации своего обработчика ошибок), что зарегистрирован другой обработчик ошибок, он немедленно отменяет регистрацию своего обработчика ошибок, чтобы ранее зарегистрированный обработчик ошибок оставался активным. Следовательно, функции, описанные в этой главе, недоступны при использовании собственного обработчика ошибок.
Ваш собственный обработчик ошибок должен следовать лучшим практикам
Ваш собственный обработчик ошибок должен игнорировать ошибки, генерируемые кодом, за который он не отвечает, например, кодом PHPUnit.
Вот код, который мы будем использовать для примеров в остальной части этой главы:
.
├── phpunit.xml
├── src
│ └── FirstPartyClass.php
├── tests
│ └── FirstPartyClassTest.php
└── vendor
├── autoload.php
└── ThirdPartyClass.php
4 directories, 5 files
<?php declare(strict_types=1);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace example;
use vendor\ThirdPartyClass;
use PHPUnit\Framework\TestCase;
final class FirstPartyClassTest extends TestCase
{
public function testOne(): void
{
$this->assertTrue((new FirstPartyClass)->method());
}
public function testTwo(): void
{
$this->assertTrue((new ThirdPartyClass)->anotherMethod());
}
}
<?php declare(strict_types=1);
namespace example;
use function trigger_error;
use vendor\ThirdPartyClass;
final class FirstPartyClass
{
public function method(): true
{
(new ThirdPartyClass)->method();
trigger_error('deprecation in first-party code', E_USER_DEPRECATED);
return true;
}
}
<?php declare(strict_types=1);
namespace vendor;
use example\FirstPartyClass;
final class ThirdPartyClass
{
public function method(): void
{
trigger_error('deprecation in third-party code', E_USER_DEPRECATED);
}
public function anotherMethod(): true
{
return (new FirstPartyClass)->method();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<phpunitxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/11.1/phpunit.xsd"
bootstrap="vendor/autoload.php"
cacheDirectory=".phpunit.cache"
>
<testsuites>
<testsuitename="default">
<directory>tests</directory>
</testsuite>
</testsuites>
</phpunit>
Запускающий тест PHPUnit выводит D, N и W соответственно для тестов, которые выполняют код, вызывающий проблему (D для устаревших функций, N для уведомлений и W для предупреждений).
Ниже приведен стандартный вывод запускающего теста PHPUnit для показанного выше примера:
$ ./tools/phpunit
PHPUnit 11.1.0 by Sebastian Bergmann and contributors.
Runtime: PHP 8.3.4
Configuration: /path/to/example/phpunit.xml
DD 1 / 1 (100%)
Time: 00:00.002, Memory: 8.00 MB
OK, but there were issues!
Tests: 2, Assertions: 2, Deprecations: 2.
Подробная информация, например, о том, где была вызвана проблема, отображается только при использовании --display-deprecations, --display-notices или --display-warnings:
$ ./tools/phpunit --display-deprecations PHPUnit 11.1.0 by Sebastian Bergmann and contributors. Runtime: PHP 8.3.4 Configuration: /path/to/example/phpunit.xml DD 1 / 1 (100%) Time: 00:00.002, Memory: 8.00 MB 2 tests triggered 2 deprecations: 1) /path/to/vendor/ThirdPartyClass.php:10 deprecation in third-party code Triggered by: * exampleFirstPartyClassTest::testOne /path/to/tests/FirstPartyClassTest.php:17 * exampleFirstPartyClassTest::testTwo /path/to/tests/FirstPartyClassTest.php:22 2) /path/to/src/FirstPartyClass.php:13 deprecation in first-party code Triggered by: * exampleFirstPartyClassTest::testOne /path/to/tests/FirstPartyClassTest.php:17 * exampleFirstPartyClassTest::testTwo /path/to/tests/FirstPartyClassTest.php:22 OK, but there were issues! Tests: 2, Assertions: 2, Deprecations: 2.
Ограничение проблем «вашим кодом»
Отчет о проблемах можно ограничить «вашим кодом», исключая код сторонних разработчиков из каталогов, таких как vendor, например. Вы можете настроить, что вы считаете «своим кодом», в файле конфигурации PHPUnit в формате XML (см. Элемент <source>):
<?xml version="1.0" encoding="UTF-8"?>
<phpunitxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/11.1/phpunit.xsd"
bootstrap="vendor/autoload.php"
cacheDirectory=".phpunit.cache"
>
<testsuites>
<testsuitename="default">
<directory>tests</directory>
</testsuite>
</testsuites>
<sourceignoreIndirectDeprecations="true"
restrictNotices="true"
restrictWarnings="true">
<include>
<directory>src</directory>
</include>
</source>
</phpunit>
Вот как будет выглядеть вывод запускающего теста PHPUnit после настройки (см. выше) для ограничения отчета о проблемах только нашим кодом:
$ ./tools/phpunit --display-deprecations PHPUnit 11.1.0 by Sebastian Bergmann and contributors. Runtime: PHP 8.3.4 Configuration: /path/to/example/phpunit.xml DD 1 / 1 (100%) Time: 00:00.002, Memory: 8.00 MB 2 tests triggered 2 deprecations: 1) /path/to/vendor/ThirdPartyClass.php:10 deprecation in third-party code Triggered by: * exampleFirstPartyClassTest::testOne /path/to/tests/FirstPartyClassTest.php:17 * exampleFirstPartyClassTest::testTwo /path/to/tests/FirstPartyClassTest.php:22 2) /path/to/src/FirstPartyClass.php:13 deprecation in first-party code Triggered by: * exampleFirstPartyClassTest::testOne /path/to/tests/FirstPartyClassTest.php:17 OK, but there were issues! Tests: 2, Assertions: 2, Deprecations: 2.
Как видно из показанного выше вывода, предупреждения, вызванные кодом сторонних разработчиков, расположенные в каталоге vendor, больше не отображаются.
Следующие атрибуты могут быть использованы в элементе <source> для настройки того, как PHPUnit использует информацию о вашем коде:
Атрибут <ignoreSelfDeprecations> позволяет игнорировать устаревшие функции, вызванные кодом первой стороны в коде первой стороны
Атрибут <ignoreDirectDeprecations> позволяет игнорировать устаревшие функции, вызванные кодом первой стороны в коде третьих сторон
Атрибут <ignoreIndirectDeprecations> позволяет игнорировать устаревшие функции, вызванные кодом третьих сторон
Атрибут <restrictNotices> позволяет игнорировать уведомления в коде третьих сторон
Атрибут <restrictWarnings> позволяет игнорировать предупреждения в коде третьих сторон
Игнорирование подавления проблем
По умолчанию обработчик ошибок, зарегистрированный запускающим тестом PHPUnit, учитывает оператор подавления (@). Это означает, что проблемы, возникающие с использованием @trigger_error(), например, не будут отображаться стандартными выводными и результативными принтерами.
Подавление проблем с использованием оператора подавления (@) можно игнорировать с помощью параметров конфигурации в файле конфигурации PHPUnit в формате XML:
Атрибут <ignoreSuppressionOfDeprecations> позволяет игнорировать подавление
E_USER_DEPRECATEDпроблемАтрибут <ignoreSuppressionOfPhpDeprecations> позволяет игнорировать подавление
E_DEPRECATEDпроблемАтрибут <ignoreSuppressionOfNotices> позволяет игнорировать подавление
E_USER_NOTICESпроблемАтрибут <ignoreSuppressionOfPhpNotices> позволяет игнорировать подавление
E_NOTICEиE_STRICTпроблемАтрибут <ignoreSuppressionOfWarnings> позволяет игнорировать подавление
E_USER_WARNINGпроблемАтрибут <ignoreSuppressionOfPhpWarnings> позволяет игнорировать подавление
E_WARNINGпроблем
Игнорирование ранее сообщённых проблем
Запускающий тест PHPUnit поддерживает объявление текущего списка проблем. Проблемы, которые находятся в этом так называемом базовом наборе, больше не будут сообщаться. Это позволяет сфокусироваться на новых проблемах, вызванных новым или изменённым кодом.
При запуске набора тестов с помощью параметра командной строки --generate-baseline запускающий тест PHPUnit запишет список всех проблем, которые возникают, в файл XML:
$ phpunit --generate-baseline baseline.xml
PHPUnit 11.1.0 by Sebastian Bergmann and contributors.
Runtime: PHP 8.2.10
Configuration: /path/to/example/phpunit.xml
D 1 / 1 (100%)
Time: 00:00.008, Memory: 4.00 MB
OK, but there were issues!
Tests: 1, Assertions: 1, Deprecations: 1.
Baseline written to /path/to/example/baseline.xml.
При запуске набора тестов с параметром командной строки --use-baseline (или если вы настроили базовый набор в вашем файле конфигурации XML для PHPUnit с помощью Атрибута <baseline>) запускающий тест PHPUnit будет использовать этот список известных проблем, чтобы пропустить их для текущего запуска:
$ phpunit --use-baseline baseline.xml
PHPUnit 11.1.0 by Sebastian Bergmann and contributors.
Runtime: PHP 8.2.10
Configuration: /path/to/example/phpunit.xml
. 1 / 1 (100%)
Time: 00:00.007, Memory: 4.00 MB
OK (1 test, 1 assertion)
2 issues were ignored by baseline.
Ожидание устаревания (E_USER_DEPRECATED)
Метод expectUserDeprecationMessage() можно использовать для ожидания возникновения проблемы устаревания E_USER_DEPRECATED со указанным сообщением.
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class DeprecationExpectationTest extends TestCase
{
public function testFailure(): void
{
$this->expectUserDeprecationMessage('the-deprecation-message');
}
}
Выполнение показанного выше теста даст следующий результат:
./tools/phpunit tests/DeprecationExpectationTest.php
PHPUnit 12.0.2 by Sebastian Bergmann and contributors.
Runtime: PHP 8.4.3
F 1 / 1 (100%)
Time: 00:00, Memory: 25.29 MB
There was 1 failure:
1) DeprecationExpectationTest::testFailure
Expected deprecation with message "the-deprecation-message" was not triggered
FAILURES!
Tests: 1, Assertions: 1, Failures: 1.
В качестве альтернативы, можно использовать $this->expectUserDeprecationMessageMatches() для ожидания возникновения проблемы E_USER_DEPRECATED, где сообщение об устаревании соответствует указанному регулярному выражению.
Это можно использовать вместе с атрибутом #[IgnoreDeprecations], чтобы не допустить провала теста.
Отключение обработчика ошибок PHPUnit
Когда вы хотите протестировать собственный обработчик ошибок или проверить, что тестируемый фрагмент кода вызывает ожидаемую ошибку, например, обработчик ошибок, зарегистрированный запуском PHPUnit, повлияет на то, чего вы хотите достичь.
Атрибут #[WithoutErrorHandler] можно использовать в таком случае, чтобы отключить обработчик ошибок PHPUnit для метода теста.
© 2005–2025 Sebastian Bergmann
Licensed under the Creative Commons Attribution 3.0 Unported License.
https://docs.phpunit.de/en/12.0/error-handling.html