diff --git a/core/modules/views/tests/src/Kernel/ViewsKernelTestBase.php b/core/modules/views/tests/src/Kernel/ViewsKernelTestBase.php index f53309bd040c53fe22d6dc9997b9bab8c03249d1..f149b7fba1fb826b743c52fcd6af07ad05c552a8 100644 --- a/core/modules/views/tests/src/Kernel/ViewsKernelTestBase.php +++ b/core/modules/views/tests/src/Kernel/ViewsKernelTestBase.php @@ -11,7 +11,7 @@ /** * Defines a base class for Views kernel testing. */ -class ViewsKernelTestBase extends KernelTestBase { +abstract class ViewsKernelTestBase extends KernelTestBase { use ViewResultAssertionTrait; diff --git a/core/phpunit.xml.dist b/core/phpunit.xml.dist index 2b45c6429fe0021fc8f23ec9b78977edd38abda3..951bd55d44b981e95add270c3d3b4edc8312ccb6 100644 --- a/core/phpunit.xml.dist +++ b/core/phpunit.xml.dist @@ -28,48 +28,16 @@ </php> <testsuites> <testsuite name="unit"> - <directory>./tests/Drupal/Tests</directory> - <directory>./modules/*/tests/src/Unit</directory> - <directory>../modules/*/tests/src/Unit</directory> - <directory>../profiles/*/tests/src/Unit</directory> - <directory>../sites/*/modules/*/tests/src/Unit</directory> - <!-- Exclude Composer's vendor directory so we don't run tests there. --> - <exclude>./vendor</exclude> - <!-- Exclude Drush tests. --> - <exclude>./drush/tests</exclude> + <file>./tests/TestSuites/UnitTestSuite.php</file> </testsuite> <testsuite name="kernel"> - <directory>./tests/Drupal/KernelTests</directory> - <directory>./modules/*/tests/src/Kernel</directory> - <directory>../modules/*/tests/src/Kernel</directory> - <directory>../profiles/*/tests/src/Kernel</directory> - <directory>../sites/*/modules/*/tests/src/Kernel</directory> - <!-- Exclude Composer's vendor directory so we don't run tests there. --> - <exclude>./vendor</exclude> - <!-- Exclude Drush tests. --> - <exclude>./drush/tests</exclude> + <file>./tests/TestSuites/KernelTestSuite.php</file> </testsuite> <testsuite name="functional"> - <directory>./tests/Drupal/FunctionalTests</directory> - <directory>./modules/*/tests/src/Functional</directory> - <directory>../modules/*/tests/src/Functional</directory> - <directory>../profiles/*/tests/src/Functional</directory> - <directory>../sites/*/modules/*/tests/src/Functional</directory> - <!-- Exclude Composer's vendor directory so we don't run tests there. --> - <exclude>./vendor</exclude> - <!-- Exclude Drush tests. --> - <exclude>./drush/tests</exclude> + <file>./tests/TestSuites/FunctionalTestSuite.php</file> </testsuite> <testsuite name="functional-javascript"> - <directory>./tests/Drupal/FunctionalJavascriptTests</directory> - <directory>./modules/*/tests/src/FunctionalJavascript</directory> - <directory>../modules/*/tests/src/FunctionalJavascript</directory> - <directory>../profiles/*/tests/src/FunctionalJavascript</directory> - <directory>../sites/*/modules/*/tests/src/FunctionalJavascript</directory> - <!-- Exclude Composer's vendor directory so we don't run tests there. --> - <exclude>./vendor</exclude> - <!-- Exclude Drush tests. --> - <exclude>./drush/tests</exclude> + <file>./tests/TestSuites/FunctionalJavascriptTestSuite.php</file> </testsuite> </testsuites> <listeners> diff --git a/core/tests/Drupal/Tests/Core/Render/RendererTestBase.php b/core/tests/Drupal/Tests/Core/Render/RendererTestBase.php index 834d0a47b2a9284920afd50a506c7b47f9c7dce9..7c5e8557d3b4bfddcf0e2a776bb92f249a1a2b18 100644 --- a/core/tests/Drupal/Tests/Core/Render/RendererTestBase.php +++ b/core/tests/Drupal/Tests/Core/Render/RendererTestBase.php @@ -22,7 +22,7 @@ /** * Base class for the actual unit tests testing \Drupal\Core\Render\Renderer. */ -class RendererTestBase extends UnitTestCase { +abstract class RendererTestBase extends UnitTestCase { /** * The tested renderer. diff --git a/core/tests/Drupal/Tests/TestSuites/TestSuiteBaseTest.php b/core/tests/Drupal/Tests/TestSuites/TestSuiteBaseTest.php new file mode 100644 index 0000000000000000000000000000000000000000..bebb4310d074fdf54ec3ae9c4b14157d2350868f --- /dev/null +++ b/core/tests/Drupal/Tests/TestSuites/TestSuiteBaseTest.php @@ -0,0 +1,134 @@ +<?php + +namespace Drupal\Tests\TestSuites; + +use org\bovigo\vfs\vfsStream; + +/** + * @coversDefaultClass \Drupal\Tests\TestSuites\TestSuiteBase + * + * @group TestSuite + */ +class TestSuiteBaseTest extends \PHPUnit_Framework_TestCase { + + /** + * Helper method to set up the file system. + * + * @return array[] + * A Drupal filesystem suitable for use with vfsStream. + */ + protected function getFilesystem() { + return [ + 'core' => [ + 'modules' => [], + 'profiles' => [], + 'tests' => [ + 'Drupal' => [ + 'NotUnitTests' => [ + 'CoreNotUnitTest.php' => '<?php', + ], + 'Tests' => [ + 'CoreUnitTest.php' => '<?php', + ], + ], + ], + ], + ]; + } + + /** + * @return array[] + * Test data for testAddTestsBySuiteNamespaceCore(). An array of arrays: + * - A filesystem array for vfsStream. + * - The sub-namespace of the test suite. + * - The array of tests expected to be discovered. + */ + public function provideCoreTests() { + $filesystem = $this->getFilesystem(); + return [ + 'unit-tests' => [ + $filesystem, + 'Unit', + [ + 'Drupal\Tests\CoreUnitTest' => 'vfs://root/core/tests/Drupal/Tests/CoreUnitTest.php', + ], + ], + 'not-unit-tests' => [ + $filesystem, + 'NotUnit', + [ + 'Drupal\NotUnitTests\CoreNotUnitTest' => 'vfs://root/core/tests/Drupal/NotUnitTests/CoreNotUnitTest.php', + ], + ], + ]; + } + + /** + * Tests for special case behavior of unit test suite namespaces in core. + * + * @covers ::addTestsBySuiteNamespace + * + * @dataProvider provideCoreTests + */ + public function testAddTestsBySuiteNamespaceCore($filesystem, $suite_namespace, $expected_tests) { + // Set up the file system. + $vfs = vfsStream::setup('root'); + vfsStream::create($filesystem, $vfs); + + // Make a stub suite base to test. + $stub = new StubTestSuiteBase('test_me'); + + // Access addTestsBySuiteNamespace(). + $ref_add_tests = new \ReflectionMethod($stub, 'addTestsBySuiteNamespace'); + $ref_add_tests->setAccessible(TRUE); + + // Invoke addTestsBySuiteNamespace(). + $ref_add_tests->invokeArgs($stub, [vfsStream::url('root'), $suite_namespace]); + + // Determine if we loaded the expected test files. + $this->assertNotEmpty($stub->testFiles); + $this->assertEmpty(array_diff_assoc($expected_tests, $stub->testFiles)); + } + +} + +/** + * Stub subclass of TestSuiteBase. + * + * We use this class to alter the behavior of TestSuiteBase so it can be + * testable. + */ +class StubTestSuiteBase extends TestSuiteBase { + + /** + * Test files discovered by addTestsBySuiteNamespace(). + * + * @var string[] + */ + public $testFiles = []; + + /** + * {@inheritdoc} + */ + protected function findExtensionDirectories($root) { + // We have to stub findExtensionDirectories() because we can't inject a + // vfsStream filesystem into drupal_phpunit_find_extension_directories(), + // which uses \SplFileInfo->getRealPath(). getRealPath() resolves + // stream-based paths to an empty string. See + // https://github.com/mikey179/vfsStream/wiki/Known-Issues + return []; + } + + /** + * {@inheritdoc} + */ + public function addTestFiles($filenames) { + // We stub addTestFiles() because the parent implementation can't deal with + // vfsStream-based filesystems due to an error in + // stream_resolve_include_path(). See + // https://github.com/mikey179/vfsStream/issues/5 Here we just store the + // test file being added in $this->testFiles. + $this->testFiles = array_merge($this->testFiles, $filenames); + } + +} diff --git a/core/tests/TestSuites/FunctionalJavascriptTestSuite.php b/core/tests/TestSuites/FunctionalJavascriptTestSuite.php new file mode 100644 index 0000000000000000000000000000000000000000..626be021830eb384066fa0d972975d5c9af1eb9f --- /dev/null +++ b/core/tests/TestSuites/FunctionalJavascriptTestSuite.php @@ -0,0 +1,27 @@ +<?php + +namespace Drupal\Tests\TestSuites; + +require_once __DIR__ . '/TestSuiteBase.php'; + +/** + * Discovers tests for the functional-javascript test suite. + */ +class FunctionalJavascriptTestSuite extends TestSuiteBase { + + /** + * Factory method which loads up a suite with all functional javascript tests. + * + * @return static + * The test suite. + */ + public static function suite() { + $root = dirname(dirname(dirname(__DIR__))); + + $suite = new static('functional-javascript'); + $suite->addTestsBySuiteNamespace($root, 'FunctionalJavascript'); + + return $suite; + } + +} diff --git a/core/tests/TestSuites/FunctionalTestSuite.php b/core/tests/TestSuites/FunctionalTestSuite.php new file mode 100644 index 0000000000000000000000000000000000000000..221a20daf9666ee13fd76de46b52fdadd5a379dd --- /dev/null +++ b/core/tests/TestSuites/FunctionalTestSuite.php @@ -0,0 +1,27 @@ +<?php + +namespace Drupal\Tests\TestSuites; + +require_once __DIR__ . '/TestSuiteBase.php'; + +/** + * Discovers tests for the functional test suite. + */ +class FunctionalTestSuite extends TestSuiteBase { + + /** + * Factory method which loads up a suite with all functional tests. + * + * @return static + * The test suite. + */ + public static function suite() { + $root = dirname(dirname(dirname(__DIR__))); + + $suite = new static('functional'); + $suite->addTestsBySuiteNamespace($root, 'Functional'); + + return $suite; + } + +} diff --git a/core/tests/TestSuites/KernelTestSuite.php b/core/tests/TestSuites/KernelTestSuite.php new file mode 100644 index 0000000000000000000000000000000000000000..2625e2b1e24f560a0bcbc31d66277b1dd1094dd9 --- /dev/null +++ b/core/tests/TestSuites/KernelTestSuite.php @@ -0,0 +1,27 @@ +<?php + +namespace Drupal\Tests\TestSuites; + +require_once __DIR__ . '/TestSuiteBase.php'; + +/** + * Discovers tests for the kernel test suite. + */ +class KernelTestSuite extends TestSuiteBase { + + /** + * Factory method which loads up a suite with all kernel tests. + * + * @return static + * The test suite. + */ + public static function suite() { + $root = dirname(dirname(dirname(__DIR__))); + + $suite = new static('kernel'); + $suite->addTestsBySuiteNamespace($root, 'Kernel'); + + return $suite; + } + +} diff --git a/core/tests/TestSuites/TestSuiteBase.php b/core/tests/TestSuites/TestSuiteBase.php new file mode 100644 index 0000000000000000000000000000000000000000..bd047e83c4d8cb0a339f2b48d912bc1e605fc70e --- /dev/null +++ b/core/tests/TestSuites/TestSuiteBase.php @@ -0,0 +1,60 @@ +<?php + +namespace Drupal\Tests\TestSuites; +use Drupal\simpletest\TestDiscovery; + +/** + * Base class for Drupal test suites. + */ +abstract class TestSuiteBase extends \PHPUnit_Framework_TestSuite { + + /** + * Finds extensions in a Drupal installation. + * + * An extension is defined as a directory with an *.info.yml file in it. + * + * @param string $root + * Path to the root of the Drupal installation. + * + * @return string[] + * Associative array of extension paths, with extension name as keys. + */ + protected function findExtensionDirectories($root) { + $extension_roots = \drupal_phpunit_contrib_extension_directory_roots($root); + + $extension_directories = array_map('drupal_phpunit_find_extension_directories', $extension_roots); + return array_reduce($extension_directories, 'array_merge', array()); + } + + /** + * Find and add tests to the suite for core and any extensions. + * + * @param string $root + * Path to the root of the Drupal installation. + * @param string $suite_namespace + * SubNamespace used to separate test suite. Examples: Unit, Functional. + */ + protected function addTestsBySuiteNamespace($root, $suite_namespace) { + // Core's tests are in the namespace Drupal\${suite_namespace}Tests\ and are + // always inside of core/tests/Drupal/${suite_namespace}Tests. The exception + // to this is Unit tests for historical reasons. + if ($suite_namespace == 'Unit') { + $this->addTestFiles(TestDiscovery::scanDirectory("Drupal\\Tests\\", "$root/core/tests/Drupal/Tests")); + } + else { + $this->addTestFiles(TestDiscovery::scanDirectory("Drupal\\${suite_namespace}Tests\\", "$root/core/tests/Drupal/${suite_namespace}Tests")); + } + + // Extensions' tests will always be in the namespace + // Drupal\Tests\$extension_name\$suite_namespace\ and be in the + // $extension_path/tests/src/$suite_namespace directory. Not all extensions + // will have all kinds of tests. + foreach ($this->findExtensionDirectories($root) as $extension_name => $dir) { + $test_path = "$dir/tests/src/$suite_namespace"; + if (is_dir($test_path)) { + $this->addTestFiles(TestDiscovery::scanDirectory("Drupal\\Tests\\$extension_name\\$suite_namespace\\", $test_path)); + } + } + } + +} diff --git a/core/tests/TestSuites/UnitTestSuite.php b/core/tests/TestSuites/UnitTestSuite.php new file mode 100644 index 0000000000000000000000000000000000000000..b05d455e473f51bd4d40e41113bdb392d3002d01 --- /dev/null +++ b/core/tests/TestSuites/UnitTestSuite.php @@ -0,0 +1,27 @@ +<?php + +namespace Drupal\Tests\TestSuites; + +require_once __DIR__ . '/TestSuiteBase.php'; + +/** + * Discovers tests for the unit test suite. + */ +class UnitTestSuite extends TestSuiteBase { + + /** + * Factory method which loads up a suite with all unit tests. + * + * @return static + * The test suite. + */ + public static function suite() { + $root = dirname(dirname(dirname(__DIR__))); + + $suite = new static('unit'); + $suite->addTestsBySuiteNamespace($root, 'Unit'); + + return $suite; + } + +} diff --git a/core/tests/bootstrap.php b/core/tests/bootstrap.php index 49e350aca75908b6fdfc9b004f065758af950e76..804aedf0bce79ee37a907d400c38c0fa95d00a71 100644 --- a/core/tests/bootstrap.php +++ b/core/tests/bootstrap.php @@ -23,7 +23,9 @@ function drupal_phpunit_find_extension_directories($scan_directory) { $dirs = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($scan_directory, \RecursiveDirectoryIterator::FOLLOW_SYMLINKS)); foreach ($dirs as $dir) { if (strpos($dir->getPathname(), '.info.yml') !== FALSE) { - // Cut off ".info.yml" from the filename for use as the extension name. + // Cut off ".info.yml" from the filename for use as the extension name. We + // use getRealPath() so that we can scan extensions represented by + // directory aliases. $extensions[substr($dir->getFilename(), 0, -9)] = $dir->getPathInfo() ->getRealPath(); } @@ -34,11 +36,16 @@ function drupal_phpunit_find_extension_directories($scan_directory) { /** * Returns directories under which contributed extensions may exist. * + * @param string $root + * (optional) Path to the root of the Drupal installation. + * * @return array * An array of directories under which contributed extensions may exist. */ -function drupal_phpunit_contrib_extension_directory_roots() { - $root = dirname(dirname(__DIR__)); +function drupal_phpunit_contrib_extension_directory_roots($root = NULL) { + if ($root === NULL) { + $root = dirname(dirname(__DIR__)); + } $paths = array( $root . '/core/modules', $root . '/core/profiles',