class DrupalListener in Drupal 9
Listens to PHPUnit test runs.
This listener orchestrates error handlers to ensure deprecations are skipped when \Drupal\Tests\Listeners\DeprecationListenerTrait::isDeprecationSkipped() returns TRUE. It removes test listeners to ensure that when \Symfony\Bridge\PhpUnit\DeprecationErrorHandler::shutdown() is run the error handler is in the expected state.
@internal
Hierarchy
- class \Drupal\Tests\Listeners\DrupalListener implements \PHPUnit\Framework\TestListener uses \PHPUnit\Framework\TestListenerDefaultImplementation, DeprecationListenerTrait, DrupalComponentTestListenerTrait, DrupalStandardsListenerTrait
Expanded class hierarchy of DrupalListener
File
- core/
tests/ Drupal/ Tests/ Listeners/ DrupalListener.php, line 24
Namespace
Drupal\Tests\ListenersView source
class DrupalListener implements TestListener {
use TestListenerDefaultImplementation;
use DeprecationListenerTrait;
use DrupalComponentTestListenerTrait;
use DrupalStandardsListenerTrait;
/**
* A list of methods to be checked for void return typehint.
*
* @var string[]
*/
protected $methodsWithVoidReturn = [
'setUpBeforeClass',
'setUp',
'assertPreConditions',
'assertPostConditions',
'tearDown',
'tearDownAfterClass',
'onNotSuccessfulTest',
];
/**
* The wrapped Symfony test listener.
*
* @var \Symfony\Bridge\PhpUnit\SymfonyTestsListener
*/
private $symfonyListener;
/**
* Constructs the DrupalListener object.
*/
public function __construct() {
$this->symfonyListener = new SymfonyTestsListener();
}
/**
* {@inheritdoc}
*/
public function startTestSuite(TestSuite $suite) : void {
$this->symfonyListener
->startTestSuite($suite);
$this
->registerErrorHandler();
}
/**
* {@inheritdoc}
*/
public function addSkippedTest(Test $test, \Throwable $t, float $time) : void {
$this->symfonyListener
->addSkippedTest($test, $t, $time);
}
/**
* {@inheritdoc}
*/
public function startTest(Test $test) : void {
// Check for deprecated @expectedDeprecation annotations before the
// Symfony error handler has a chance to swallow this deprecation notice.
$annotations = UtilTest::parseTestMethodAnnotations(get_class($test), $test
->getName(FALSE));
if (isset($annotations['method']['expectedDeprecation'])) {
@trigger_error('The @expectedDeprecation annotation on ' . get_class($test) . '::' . $test
->getName(FALSE) . '() is deprecated in drupal:9.1.0 and is removed from drupal:10.0.0. Use the expectDeprecation() method instead. See https://www.drupal.org/node/3176667', E_USER_DEPRECATED);
}
// The Drupal error handler has to be registered prior to the Symfony error
// handler that is registered in
// \Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait::startTest()
// that handles expected deprecations.
$this
->registerErrorHandler();
$this->symfonyListener
->startTest($test);
// Check for missing void return typehints in concrete test classes'
// methods. If the method is inherited from a base test class, do
// nothing.
$class = new \ReflectionClass($test);
foreach ($this->methodsWithVoidReturn as $method) {
if ($class
->hasMethod($method)) {
$reflected_method = $class
->getMethod($method);
if ($reflected_method
->getDeclaringClass()
->getName() === get_class($test)) {
if (!$reflected_method
->hasReturnType() || $reflected_method
->getReturnType()
->getName() !== 'void') {
@trigger_error("Declaring ::{$method} without a void return typehint in " . get_class($test) . " is deprecated in drupal:9.0.0. Typehinting will be required before drupal:10.0.0. See https://www.drupal.org/node/3114724", E_USER_DEPRECATED);
}
}
}
}
// Check for incorrect visibility of the $modules property.
if ($class
->hasProperty('modules') && !$class
->getProperty('modules')
->isProtected()) {
@trigger_error('The ' . get_class($test) . '::$modules property must be declared protected. See https://www.drupal.org/node/2909426', E_USER_DEPRECATED);
}
}
/**
* {@inheritdoc}
*/
public function endTest(Test $test, float $time) : void {
if (!SymfonyTestsListenerTrait::$previousErrorHandler) {
$className = get_class($test);
$groups = UtilTest::getGroups($className, $test
->getName(FALSE));
if (in_array('legacy', $groups, TRUE)) {
// If the Symfony listener is not registered for legacy tests then
// deprecations triggered by the DebugClassloader in
// \Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait::endTest()
// are not correctly identified as occurring in legacy tests.
$symfony_error_handler = set_error_handler([
SymfonyTestsListenerTrait::class,
'handleError',
]);
}
}
$this
->deprecationEndTest($test, $time);
$this->symfonyListener
->endTest($test, $time);
$this
->componentEndTest($test, $time);
$this
->standardsEndTest($test, $time);
if (isset($symfony_error_handler)) {
// If this test listener has added the Symfony error handler then it needs
// to be removed.
restore_error_handler();
}
// The Drupal error handler has to be removed after the Symfony error
// handler is potentially removed in
// \Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait::endTest().
$this
->removeErrorHandler();
}
}
Members
Name![]() |
Modifiers | Type | Description | Overrides |
---|---|---|---|---|
DeprecationListenerTrait:: |
private | property | The previous error handler. | |
DeprecationListenerTrait:: |
protected | function | Reacts to the end of a test. | |
DeprecationListenerTrait:: |
public static | function | A list of deprecations to ignore whilst fixes are put in place. | |
DeprecationListenerTrait:: |
public static | function | Determines if a deprecation error should be skipped. | |
DeprecationListenerTrait:: |
protected | function | Registers an error handler that wraps Symfony's DeprecationErrorHandler. | |
DeprecationListenerTrait:: |
protected | function | Removes the error handler if registered. | |
DrupalComponentTestListenerTrait:: |
protected | function | Reacts to the end of a test. | |
DrupalListener:: |
protected | property | A list of methods to be checked for void return typehint. | |
DrupalListener:: |
private | property | The wrapped Symfony test listener. | |
DrupalListener:: |
public | function | ||
DrupalListener:: |
public | function | ||
DrupalListener:: |
public | function | ||
DrupalListener:: |
public | function | ||
DrupalListener:: |
public | function | Constructs the DrupalListener object. | |
DrupalStandardsListenerTrait:: |
private | function | Check an individual test run for valid @covers annotation. | |
DrupalStandardsListenerTrait:: |
private | function | Helper method to check if a string names a valid class or trait. | |
DrupalStandardsListenerTrait:: |
private | function | Reacts to the end of a test. | |
DrupalStandardsListenerTrait:: |
public static | function | Handles errors to ensure deprecation messages are not triggered. | |
DrupalStandardsListenerTrait:: |
private | function | Signals a coding standards failure to the user. | |
DrupalStandardsListenerTrait:: |
private | function | Determine if a test object is a test suite regardless of PHPUnit version. | |
DrupalStandardsListenerTrait:: |
protected | function | Reacts to the end of a test. |