mirror of
https://github.com/moodle/moodle.git
synced 2025-04-20 07:56:06 +02:00
MDL-71036 phpunit: Remove custom autoloader
Custom autoloaders are deprecated with PHPUnit 9 and will be removed with PHPUnit 10. Since PHPUnit 8.5 custom autoloaders don't do much because that version removed the ability to launch unit tests by class name and that's exactly the reason we had a custom autoloader (to map class names to files within our tests). See MDL-67673 about when direct use of classes was deprecated (8.5), now removed (9.5). So, as far as it's unused, removing it now, test still can be selectively using any of: - a relative path to file (although there are some restrictions comming with PHPUnit 9, see https://github.com/sebastianbergmann/phpunit/issues/4105 - using --filter, to point to any classname[::method] - using --testsuite to run a complete suite - using --config to point to custom components. Also, commented out the lib/ajax/tests directory because it doesn't exist / is empty and PHPUnit 9 emits error when a configured test directory does not exist. See https://github.com/sebastianbergmann/phpunit/issues/4493. Alternative was to completely remove the configuration line, but decided to keep it around in case some day we want to add some test there.
This commit is contained in:
parent
8a3663b175
commit
be30af0e23
@ -50,7 +50,6 @@ if (!defined('IGNORE_COMPONENT_CACHE')) {
|
||||
|
||||
require_once(__DIR__.'/bootstraplib.php');
|
||||
require_once(__DIR__.'/../testing/lib.php');
|
||||
require_once(__DIR__.'/classes/autoloader.php');
|
||||
|
||||
if (isset($_SERVER['REMOTE_ADDR'])) {
|
||||
phpunit_bootstrap_error(1, 'Unit tests can be executed only from command line!');
|
||||
|
@ -1,203 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* PHPUnit autoloader for Moodle.
|
||||
*
|
||||
* @package core
|
||||
* @category phpunit
|
||||
* @copyright 2013 Petr Skoda {@link http://skodak.org}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class phpunit_autoloader.
|
||||
*
|
||||
* Please notice that phpunit testcases obey frankenstyle naming rules,
|
||||
* that is full component prefix + _testcase postfix. The files are expected
|
||||
* in tests directory inside each component. There are some extra tests
|
||||
* directories which require both classname and file path.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* vendor/bin/phpunit core_component_testcase
|
||||
* vendor/bin/phpunit lib/tests/component_test.php
|
||||
* vendor/bin/phpunit core_component_testcase lib/tests/component_test.php
|
||||
*
|
||||
* @package core
|
||||
* @category phpunit
|
||||
* @copyright 2013 Petr Skoda {@link http://skodak.org}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class phpunit_autoloader implements \PHPUnit\Runner\TestSuiteLoader {
|
||||
public function load(string $suiteClassName, string $suiteClassFile = ''): ReflectionClass {
|
||||
global $CFG;
|
||||
|
||||
// Let's guess what user entered on the commandline...
|
||||
if ($suiteClassFile) {
|
||||
// This means they either entered the class+path or path only.
|
||||
if (strpos($suiteClassName, '/') !== false) {
|
||||
// Class names can not contain slashes,
|
||||
// user entered only path without testcase class name.
|
||||
return $this->guess_class_from_path($suiteClassFile);
|
||||
}
|
||||
if (strpos($suiteClassName, '\\') !== false and strpos($suiteClassFile, $suiteClassName.'.php') !== false) {
|
||||
// This must be backslashed windows path.
|
||||
return $this->guess_class_from_path($suiteClassFile);
|
||||
}
|
||||
}
|
||||
|
||||
if (class_exists($suiteClassName, false)) {
|
||||
$class = new ReflectionClass($suiteClassName);
|
||||
return $class;
|
||||
}
|
||||
|
||||
if ($suiteClassFile) {
|
||||
PHPUnit\Util\Fileloader::checkAndLoad($suiteClassFile);
|
||||
if (class_exists($suiteClassName, false)) {
|
||||
$class = new ReflectionClass($suiteClassName);
|
||||
return $class;
|
||||
}
|
||||
|
||||
throw new PHPUnit\Framework\Exception(
|
||||
sprintf("Class '%s' could not be found in '%s'.", $suiteClassName, $suiteClassFile)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Try standard testcase naming rules based on frankenstyle component:
|
||||
* 1/ test classes should use standard frankenstyle class names plus suffix "_testcase"
|
||||
* 2/ test classes should be stored in files with suffix "_test"
|
||||
*/
|
||||
|
||||
$parts = explode('_', $suiteClassName);
|
||||
$suffix = end($parts);
|
||||
$component = '';
|
||||
|
||||
if ($suffix === 'testcase') {
|
||||
unset($parts[key($parts)]);
|
||||
while($parts) {
|
||||
if (!$component) {
|
||||
$component = array_shift($parts);
|
||||
} else {
|
||||
$component = $component . '_' . array_shift($parts);
|
||||
}
|
||||
// Try standard plugin and core subsystem locations.
|
||||
if ($fulldir = core_component::get_component_directory($component)) {
|
||||
$testfile = implode('_', $parts);
|
||||
$fullpath = "{$fulldir}/tests/{$testfile}_test.php";
|
||||
if (is_readable($fullpath)) {
|
||||
include_once($fullpath);
|
||||
if (class_exists($suiteClassName, false)) {
|
||||
$class = new ReflectionClass($suiteClassName);
|
||||
return $class;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// The last option is testsuite directories in main phpunit.xml file.
|
||||
$xmlfile = "$CFG->dirroot/phpunit.xml";
|
||||
if (is_readable($xmlfile) and $xml = file_get_contents($xmlfile)) {
|
||||
$dom = new DOMDocument();
|
||||
$dom->loadXML($xml);
|
||||
$nodes = $dom->getElementsByTagName('testsuite');
|
||||
foreach ($nodes as $node) {
|
||||
/** @var DOMNode $node */
|
||||
$suitename = trim($node->attributes->getNamedItem('name')->nodeValue);
|
||||
if (strpos($suitename, 'core') !== 0 or strpos($suitename, ' ') !== false) {
|
||||
continue;
|
||||
}
|
||||
// This is a nasty hack: testsuit names are sometimes used as prefix for testcases
|
||||
// in non-standard core subsystem locations.
|
||||
if (strpos($suiteClassName, $suitename) !== 0) {
|
||||
continue;
|
||||
}
|
||||
foreach ($node->childNodes as $dirnode) {
|
||||
/** @var DOMNode $dirnode */
|
||||
$dir = trim($dirnode->textContent);
|
||||
if (!$dir) {
|
||||
continue;
|
||||
}
|
||||
$dir = $CFG->dirroot.'/'.$dir;
|
||||
$parts = explode('_', $suitename);
|
||||
$prefix = '';
|
||||
while ($parts) {
|
||||
if ($prefix) {
|
||||
$prefix = $prefix.'_'.array_shift($parts);
|
||||
} else {
|
||||
$prefix = array_shift($parts);
|
||||
}
|
||||
$filename = substr($suiteClassName, strlen($prefix)+1);
|
||||
$filename = preg_replace('/testcase$/', 'test', $filename);
|
||||
if (is_readable("$dir/$filename.php")) {
|
||||
include_once("$dir/$filename.php");
|
||||
if (class_exists($suiteClassName, false)) {
|
||||
$class = new ReflectionClass($suiteClassName);
|
||||
return $class;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new PHPUnit\Framework\Exception(
|
||||
sprintf("Class '%s' could not be found in '%s'.", $suiteClassName, $suiteClassFile)
|
||||
);
|
||||
}
|
||||
|
||||
protected function guess_class_from_path($file) {
|
||||
// Somebody is using just the file name, we need to look inside the file and guess the testcase
|
||||
// class name. Let's throw fatal error if there are more testcases in one file.
|
||||
|
||||
$classes = get_declared_classes();
|
||||
PHPUnit\Util\Fileloader::checkAndLoad($file);
|
||||
$includePathFilename = stream_resolve_include_path($file);
|
||||
$loadedClasses = array_diff(get_declared_classes(), $classes);
|
||||
|
||||
$candidates = array();
|
||||
|
||||
foreach ($loadedClasses as $loadedClass) {
|
||||
$class = new ReflectionClass($loadedClass);
|
||||
|
||||
if ($class->isSubclassOf('PHPUnit\Framework\TestCase') and !$class->isAbstract()) {
|
||||
if (realpath($includePathFilename) === realpath($class->getFileName())) {
|
||||
$candidates[] = $loadedClass;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count($candidates) == 0) {
|
||||
throw new PHPUnit\Framework\Exception(
|
||||
sprintf("File '%s' does not contain any test cases.", $file)
|
||||
);
|
||||
}
|
||||
|
||||
if (count($candidates) > 1) {
|
||||
throw new PHPUnit\Framework\Exception(
|
||||
sprintf("File '%s' contains multiple test cases: ".implode(', ', $candidates), $file)
|
||||
);
|
||||
}
|
||||
|
||||
$classname = reset($candidates);
|
||||
return new ReflectionClass($classname);
|
||||
}
|
||||
|
||||
public function reload(ReflectionClass $aClass): ReflectionClass {
|
||||
return $aClass;
|
||||
}
|
||||
}
|
@ -16,7 +16,6 @@
|
||||
stopOnSkipped="false"
|
||||
beStrictAboutTestsThatDoNotTestAnything="false"
|
||||
beStrictAboutOutputDuringTests="true"
|
||||
testSuiteLoaderClass="phpunit_autoloader"
|
||||
>
|
||||
|
||||
<php>
|
||||
@ -45,7 +44,7 @@
|
||||
</testsuite>
|
||||
<testsuite name="core_testsuite">
|
||||
<directory suffix="_test.php">lib/tests</directory>
|
||||
<directory suffix="_test.php">lib/ajax/tests</directory>
|
||||
<!-- <directory suffix="_test.php">lib/ajax/tests</directory> -->
|
||||
</testsuite>
|
||||
<testsuite name="core_favourites_testsuite">
|
||||
<directory suffix="_test.php">favourites/tests</directory>
|
||||
|
Loading…
x
Reference in New Issue
Block a user