You are here

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.



Expanded class hierarchy of DrupalListener


core/tests/Drupal/Tests/Listeners/DrupalListener.php, line 24


View 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 = [

   * 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 {

   * {@inheritdoc}
  public function addSkippedTest(Test $test, \Throwable $t, float $time) : void {
      ->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
    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', 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.

    // 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
        if ($reflected_method
          ->getName() === get_class($test)) {
          if (!$reflected_method
            ->hasReturnType() || $reflected_method
            ->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", E_USER_DEPRECATED);

    // Check for incorrect visibility of the $modules property.
    if ($class
      ->hasProperty('modules') && !$class
      ->isProtected()) {
      @trigger_error('The ' . get_class($test) . '::$modules property must be declared protected. See', E_USER_DEPRECATED);

   * {@inheritdoc}
  public function endTest(Test $test, float $time) : void {
    if (!SymfonyTestsListenerTrait::$previousErrorHandler) {
      $className = get_class($test);
      $groups = UtilTest::getGroups($className, $test
      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([
      ->deprecationEndTest($test, $time);
      ->endTest($test, $time);
      ->componentEndTest($test, $time);
      ->standardsEndTest($test, $time);
    if (isset($symfony_error_handler)) {

      // If this test listener has added the Symfony error handler then it needs
      // to be removed.

    // The Drupal error handler has to be removed after the Symfony error
    // handler is potentially removed in
    // \Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait::endTest().



Namesort descending Modifiers Type Description Overrides
DeprecationListenerTrait::$previousHandler private property The previous error handler.
DeprecationListenerTrait::deprecationEndTest protected function Reacts to the end of a test.
DeprecationListenerTrait::getSkippedDeprecations public static function A list of deprecations to ignore whilst fixes are put in place.
DeprecationListenerTrait::isDeprecationSkipped public static function Determines if a deprecation error should be skipped.
DeprecationListenerTrait::registerErrorHandler protected function Registers an error handler that wraps Symfony's DeprecationErrorHandler.
DeprecationListenerTrait::removeErrorHandler protected function Removes the error handler if registered.
DrupalComponentTestListenerTrait::componentEndTest protected function Reacts to the end of a test.
DrupalListener::$methodsWithVoidReturn protected property A list of methods to be checked for void return typehint.
DrupalListener::$symfonyListener private property The wrapped Symfony test listener.
DrupalListener::addSkippedTest public function
DrupalListener::endTest public function
DrupalListener::startTest public function
DrupalListener::startTestSuite public function
DrupalListener::__construct public function Constructs the DrupalListener object.
DrupalStandardsListenerTrait::checkValidCoversForTest private function Check an individual test run for valid @covers annotation.
DrupalStandardsListenerTrait::classExists private function Helper method to check if a string names a valid class or trait.
DrupalStandardsListenerTrait::doEndTest private function Reacts to the end of a test.
DrupalStandardsListenerTrait::errorHandler public static function Handles errors to ensure deprecation messages are not triggered.
DrupalStandardsListenerTrait::fail private function Signals a coding standards failure to the user.
DrupalStandardsListenerTrait::isTestSuite private function Determine if a test object is a test suite regardless of PHPUnit version.
DrupalStandardsListenerTrait::standardsEndTest protected function Reacts to the end of a test.