Issue #3031577 by alexpott, Lendude, larowlan: \Drupal\Tests\Listeners\DeprecationListenerTrait::getSkippedDeprecations() does not work in unit tests

merge-requests/1119/head
Nathaniel Catchpole 2019-03-28 11:06:40 +00:00
parent 0df3be0e23
commit 51cc6680c8
4 changed files with 131 additions and 0 deletions

View File

@ -0,0 +1,33 @@
<?php
namespace Drupal\Tests\Listeners;
use PHPUnit\Framework\Test;
use PHPUnit\Framework\TestListener;
use PHPUnit\Framework\TestListenerDefaultImplementation;
if (class_exists('PHPUnit_Runner_Version') && version_compare(\PHPUnit_Runner_Version::id(), '6.0.0', '<')) {
class_alias('Drupal\Tests\Listeners\Legacy\AfterSymfonyListener', 'Drupal\Tests\Listeners\AfterSymfonyListener');
// Using an early return instead of an else does not work when using the
// PHPUnit phar due to some weird PHP behavior (the class gets defined without
// executing the code before it and so the definition is not properly
// conditional).
}
else {
/**
* Listens to PHPUnit test runs.
*
* @internal
*/
class AfterSymfonyListener implements TestListener {
use TestListenerDefaultImplementation;
/**
* {@inheritdoc}
*/
public function endTest(Test $test, $time) {
restore_error_handler();
}
}
}

View File

@ -13,10 +13,21 @@ use PHPUnit\Framework\TestCase;
* fixed. * fixed.
*/ */
trait DeprecationListenerTrait { trait DeprecationListenerTrait {
use ExpectDeprecationTrait; use ExpectDeprecationTrait;
/**
* The previous error handler.
*
* @var callable
*/
private $previousHandler;
protected function deprecationStartTest($test) { protected function deprecationStartTest($test) {
if ($test instanceof \PHPUnit_Framework_TestCase || $test instanceof TestCase) { if ($test instanceof \PHPUnit_Framework_TestCase || $test instanceof TestCase) {
if ('disabled' !== getenv('SYMFONY_DEPRECATIONS_HELPER')) {
$this->registerErrorHandler($test);
}
if ($this->willBeIsolated($test)) { if ($this->willBeIsolated($test)) {
putenv('DRUPAL_EXPECTED_DEPRECATIONS_SERIALIZE=' . tempnam(sys_get_temp_dir(), 'exdep')); putenv('DRUPAL_EXPECTED_DEPRECATIONS_SERIALIZE=' . tempnam(sys_get_temp_dir(), 'exdep'));
} }
@ -126,6 +137,8 @@ trait DeprecationListenerTrait {
// is a Windows only deprecation. Remove when core no longer uses // is a Windows only deprecation. Remove when core no longer uses
// WinCacheClassLoader in \Drupal\Core\DrupalKernel::initializeSettings(). // WinCacheClassLoader in \Drupal\Core\DrupalKernel::initializeSettings().
'The Symfony\Component\ClassLoader\WinCacheClassLoader class is deprecated since Symfony 3.3 and will be removed in 4.0. Use `composer install --apcu-autoloader` instead.', 'The Symfony\Component\ClassLoader\WinCacheClassLoader class is deprecated since Symfony 3.3 and will be removed in 4.0. Use `composer install --apcu-autoloader` instead.',
// The following deprecation message is skipped for testing purposes.
'\Drupal\Tests\SkippedDeprecationTest deprecation',
// These deprecations are triggered by symfony/psr-http-message-factory // These deprecations are triggered by symfony/psr-http-message-factory
// 1.2, which can be installed if you update dependencies on php 7 or // 1.2, which can be installed if you update dependencies on php 7 or
// higher // higher
@ -134,4 +147,40 @@ trait DeprecationListenerTrait {
]; ];
} }
/**
* Registers an error handler that wraps Symfony's DeprecationErrorHandler.
*
* @see \Symfony\Bridge\PhpUnit\DeprecationErrorHandler
* @see \Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait
*/
protected function registerErrorHandler($test) {
$deprecation_handler = function ($type, $msg, $file, $line, $context = []) {
// Skip listed deprecations.
if ($type === E_USER_DEPRECATED && in_array($msg, self::getSkippedDeprecations(), TRUE)) {
return;
}
return call_user_func($this->previousHandler, $type, $msg, $file, $line, $context);
};
if ($this->previousHandler) {
set_error_handler($deprecation_handler);
return;
}
$this->previousHandler = set_error_handler($deprecation_handler);
// Register another listener so that we can remove the error handler before
// Symfony's DeprecationErrorHandler checks that it is the currently
// registered handler. Note this is done like this to ensure the error
// handler is removed after SymfonyTestsListenerTrait::endTest() is called.
// SymfonyTestsListenerTrait has its own error handler that needs to be
// removed before this one.
$test_result_object = $test->getTestResultObject();
$reflection_class = new \ReflectionClass($test_result_object);
$reflection_property = $reflection_class->getProperty('listeners');
$reflection_property->setAccessible(TRUE);
$listeners = $reflection_property->getValue($test_result_object);
$listeners[] = new AfterSymfonyListener();
$reflection_property->setValue($test_result_object, $listeners);
}
} }

View File

@ -0,0 +1,19 @@
<?php
namespace Drupal\Tests\Listeners\Legacy;
/**
* Listens to PHPUnit test runs.
*
* @internal
*/
class AfterSymfonyListener extends \PHPUnit_Framework_BaseTestListener {
/**
* {@inheritdoc}
*/
public function endTest(\PHPUnit_Framework_Test $test, $time) {
restore_error_handler();
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace Drupal\Tests;
/**
* @group Test
*/
class SkippedDeprecationTest extends UnitTestCase {
/**
* Tests skipping deprecations in unit tests.
*
* @see \Drupal\Tests\Listeners\DeprecationListenerTrait::getSkippedDeprecations()
*/
public function testSkippingDeprecations() {
@trigger_error('\Drupal\Tests\SkippedDeprecationTest deprecation', E_USER_DEPRECATED);
$this->addToAssertionCount(1);
}
/**
* Tests skipping deprecations in unit tests multiple times.
*
* @see \Drupal\Tests\Listeners\DeprecationListenerTrait::getSkippedDeprecations()
*/
public function testSkippingDeprecationsAgain() {
@trigger_error('\Drupal\Tests\SkippedDeprecationTest deprecation', E_USER_DEPRECATED);
$this->addToAssertionCount(1);
}
}