Skip to content

Instantly share code, notes, and snippets.

@upyx
Created February 8, 2024 10:29
Show Gist options
  • Save upyx/372bd015bd2ba087189f6d0152eca7eb to your computer and use it in GitHub Desktop.
Save upyx/372bd015bd2ba087189f6d0152eca7eb to your computer and use it in GitHub Desktop.
Simple PHPUnit 10+ extension to restore an error handler overrined by Symfony's one
<?php
declare(strict_types=1);
namespace App\Tests\PhpUnit;
use PHPUnit\Event\Test\Finished;
use PHPUnit\Event\Test\FinishedSubscriber;
use PHPUnit\Event\Test\Prepared;
use PHPUnit\Event\Test\PreparedSubscriber;
use PHPUnit\Metadata\Parser\Registry as MetadataRegistry;
use PHPUnit\Runner\ErrorHandler;
use PHPUnit\Runner\Extension\Extension as PhpUnitExtension;
use PHPUnit\Runner\Extension\Facade;
use PHPUnit\Runner\Extension\ParameterCollection;
use PHPUnit\TextUI\Configuration\Configuration;
use Symfony\Bridge\PhpUnit\DeprecationErrorHandler;
use function restore_error_handler;
use function set_error_handler;
final class Extension implements PhpUnitExtension {
private static bool $errorHandlerWrapped = false;
public static function enablePhpUnitErrorHandler(): void {
if (self::$errorHandlerWrapped) {
return;
}
$errorHandler = set_error_handler('intval');
restore_error_handler();
if (!isset($errorHandler[0]) || $errorHandler instanceof DeprecationErrorHandler) {
return;
}
set_error_handler(static function ($type, $msg, $file, $line) use ($errorHandler) {
$errorHandler($type, $msg, $file, $line);
return ErrorHandler::instance()($type, $msg, $file, $line);
});
self::$errorHandlerWrapped = true;
}
public static function disablePhpUnitErrorHandler(): void {
if (self::$errorHandlerWrapped) {
self::$errorHandlerWrapped = false;
restore_error_handler();
}
}
public function bootstrap(Configuration $configuration, Facade $facade, ParameterCollection $parameters): void {
$facade->registerSubscriber(
new class() implements PreparedSubscriber {
public function notify(Prepared $event): void {
$test = $event->test();
if (!$test->isTestMethod()) {
return;
}
$shouldErrorHandlerBeUsed = !MetadataRegistry::parser()
->forMethod($test->className(), $test->methodName())
->isWithoutErrorHandler()
->isNotEmpty();
if ($shouldErrorHandlerBeUsed) {
Extension::enablePhpUnitErrorHandler();
}
}
}
);
$facade->registerSubscriber(
new class() implements FinishedSubscriber {
public function notify(Finished $event): void {
Extension::disablePhpUnitErrorHandler();
}
}
);
self::disablePhpUnitErrorHandler();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<phpunit>
<!-- ... -->
<extensions>
<bootstrap class="App\Tests\PhpUnit\Extension"/> <!-- use correct path to the extension -->
</extensions>
</phpunit>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment