Unit tests: Support unit tests in extensions and skins
authorKosta Harlan <kharlan@wikimedia.org>
Mon, 1 Jul 2019 19:33:54 +0000 (15:33 -0400)
committerKosta Harlan <kharlan@wikimedia.org>
Mon, 1 Jul 2019 20:21:01 +0000 (16:21 -0400)
For now only extensions with skin/extension.json which follow PSR-4 are
supported.

DefaultSettings is loaded in bootstrap to work around errors when unit tests are
run followed by integration tests (e.g. `vendor/bin/phpunit`)

Usage:

 - composer phpunit:unit will run all unit tests in core and any tests in
   `{extensions/skins}/tests/phpunit/unit` which also extend
   MediaWikiUnitTestCase, and which have an extension.json file
- Pass a specific directory to only run unit tests for a particular extension,
   e.g. `composer phpunit:unit -- extensions/GrowthExperiments`

Bug: T226911
Change-Id: I237a9f82e4d1b05cf2f08b3e4bb7ffcd8d47111c

includes/registration/ExtensionRegistry.php
phpunit.xml.dist
tests/phpunit/bootstrap.php

index 768b488..9cae73c 100644 (file)
@@ -300,6 +300,13 @@ class ExtensionRegistry {
                        }
 
                        $dir = dirname( $path );
+                       self::exportAutoloadClassesAndNamespaces(
+                               $dir,
+                               $info,
+                               $autoloadClasses,
+                               $autoloadNamespaces
+                       );
+
                        if ( isset( $info['AutoloadClasses'] ) ) {
                                $autoload = $this->processAutoLoader( $dir, $info['AutoloadClasses'] );
                                $GLOBALS['wgAutoloadClasses'] += $autoload;
@@ -347,6 +354,28 @@ class ExtensionRegistry {
                return $data;
        }
 
+       /**
+        * Export autoload classes and namespaces for a given directory and parsed JSON info file.
+        *
+        * @param string $dir
+        * @param array $info
+        * @param array &$autoloadClasses
+        * @param array &$autoloadNamespaces
+        */
+       public static function exportAutoloadClassesAndNamespaces(
+               $dir, $info, &$autoloadClasses = [], &$autoloadNamespaces = []
+       ) {
+               if ( isset( $info['AutoloadClasses'] ) ) {
+                       $autoload = self::processAutoLoader( $dir, $info['AutoloadClasses'] );
+                       $GLOBALS['wgAutoloadClasses'] += $autoload;
+                       $autoloadClasses += $autoload;
+               }
+               if ( isset( $info['AutoloadNamespaces'] ) ) {
+                       $autoloadNamespaces += self::processAutoLoader( $dir, $info['AutoloadNamespaces'] );
+                       AutoLoader::$psr4Namespaces += $autoloadNamespaces;
+               }
+       }
+
        protected function exportExtractedData( array $info ) {
                foreach ( $info['globals'] as $key => $val ) {
                        // If a merge strategy is set, read it and remove it from the value
@@ -511,7 +540,7 @@ class ExtensionRegistry {
         * @param array $files
         * @return array
         */
-       protected function processAutoLoader( $dir, array $files ) {
+       protected static function processAutoLoader( $dir, array $files ) {
                // Make paths absolute, relative to the JSON file
                foreach ( $files as &$file ) {
                        $file = "$dir/$file";
index e160f3b..159adbc 100644 (file)
        <testsuites>
                <testsuite name="unit">
                        <directory>tests/phpunit/unit</directory>
+                       <directory>**/**/tests/phpunit/unit</directory>
                </testsuite>
                <testsuite name="integration">
                        <directory>tests/phpunit/integration</directory>
+                       <directory>**/**/tests/phpunit/integration</directory>
                </testsuite>
        </testsuites>
        <groups>
index 4b1ade2..10348d4 100644 (file)
@@ -66,3 +66,23 @@ require_once "$IP/tests/common/TestSetup.php";
 wfRequireOnceInGlobalScope( "$IP/includes/AutoLoader.php" );
 wfRequireOnceInGlobalScope( "$IP/tests/common/TestsAutoLoader.php" );
 wfRequireOnceInGlobalScope( "$IP/includes/Defines.php" );
+wfRequireOnceInGlobalScope( "$IP/includes/DefaultSettings.php" );
+
+// Load extensions/skins present in filesystem so that classes can be discovered.
+$directoryToJsonMap = [
+       'extensions' => [ 'extension.json', 'extension-wip.json' ],
+       'skins' => [ 'skin.json', 'skin-wip.json' ]
+];
+foreach ( $directoryToJsonMap as $directory => $jsonFile ) {
+       foreach ( new DirectoryIterator( __DIR__ . '/../../' . $directory ) as $iterator ) {
+               foreach ( $jsonFile as $file ) {
+                       $jsonPath = $iterator->getPathname() . '/' . $file;
+                       if ( file_exists( $jsonPath ) ) {
+                               $json = file_get_contents( $jsonPath );
+                               $info = json_decode( $json, true );
+                               $dir = dirname( $jsonPath );
+                               ExtensionRegistry::exportAutoloadClassesAndNamespaces( $dir, $info );
+                       }
+               }
+       }
+}