MDL-66903 testing: Add support for a \tests\ namespace during tests

This commit:
- introduces a \tests\ sub-namespace for use in unit tests only
- the path to this the tests/classes directory of the owning parent
- files here are excluded from unit test runs

This is agreed per policy in MDL-80855.
This commit is contained in:
Andrew Nicols 2023-12-19 22:59:15 +08:00
parent 3c03e9448c
commit 406dcd2566
No known key found for this signature in database
GPG Key ID: 6D1E3157C8CFBF14
5 changed files with 177 additions and 0 deletions

View File

@ -0,0 +1,10 @@
issueNumber: MDL-66903
notes:
core:
- message: >
Added the ability for unit tests to autoload classes in the
`\[component]\tests\`
namespace from the `[path/to/component]/tests/classes` directory.
type: improved

View File

@ -172,6 +172,38 @@ class core_component {
require($file);
return;
}
if (PHPUNIT_TEST) {
// For unit tests we support classes in `\frankenstyle_component\tests\` to be loaded from
// `path/to/frankenstyle/component/tests/classes` directory.
// Note: We do *not* support the legacy `\frankenstyle_component_tests_style_classnames`.
if ($component = self::get_component_from_classname($classname)) {
$pathoptions = [
'/tests/classes' => "{$component}\\tests\\",
'/tests/behat' => "{$component}\\behat\\",
];
foreach ($pathoptions as $path => $testnamespace) {
if (preg_match("#^" . preg_quote($testnamespace) . "#", $classname)) {
$path = self::get_component_directory($component) . $path;
$relativeclassname = str_replace(
$testnamespace,
'',
$classname,
);
$file = sprintf(
"%s/%s.php",
$path,
str_replace('\\', '/', $relativeclassname),
);
if (!empty($file) && file_exists($file)) {
require($file);
return;
}
break;
}
}
}
}
}
/**

View File

@ -529,6 +529,7 @@ class phpunit_util extends testing_util {
$template = <<<EOF
<testsuite name="@component@_testsuite">
<directory suffix="_test.php">@dir@</directory>
<exclude>@dir@/classes</exclude>
</testsuite>
EOF;
@ -621,6 +622,7 @@ class phpunit_util extends testing_util {
<testsuites>
<testsuite name="@component@_testsuite">
<directory suffix="_test.php">.</directory>
<exclude>./classes</exclude>
</testsuite>
</testsuites>
EOT;

View File

@ -914,6 +914,69 @@ final class component_test extends advanced_testcase {
];
}
/**
* Test that the classloader can load from the test namespaces.
*/
public function test_classloader_tests_namespace(): void {
global $CFG;
$this->resetAfterTest();
$getclassfilecontent = function (string $classname, ?string $namespace): string {
if ($namespace) {
$content = "<?php\nnamespace $namespace;\nclass $classname {}";
} else {
$content = "<?php\nclass $classname {}";
}
return $content;
};
$vfileroot = \org\bovigo\vfs\vfsStream::setup('root', null, [
'lib' => [
'classes' => [
'example.php' => $getclassfilecontent('example', 'core'),
],
'tests' => [
'classes' => [
'example_classname.php' => $getclassfilecontent('example_classname', \core\tests::class),
],
'behat' => [
'example_classname.php' => $getclassfilecontent('example_classname', \core\behat::class),
],
],
],
]);
// Note: This is pretty hacky, but it's the only way to test the classloader.
// We have to override the dirroot and libdir, and then reset the plugintypes property.
$CFG->dirroot = $vfileroot->url();
$CFG->libdir = $vfileroot->url() . '/lib';
(new ReflectionProperty('core_component', 'plugintypes'))->setValue(null, null);
// Existing classes do not break.
$this->assertTrue(
class_exists(\core\example::class),
);
// Test and behat classes work.
$this->assertTrue(
class_exists(\core\tests\example_classname::class),
);
$this->assertTrue(
class_exists(\core\behat\example_classname::class),
);
// Non-existent classes do not do anything.
$this->assertFalse(
class_exists(\core\tests\example_classname_not_found::class),
);
}
public function tearDown(): void {
$plugintypes = new ReflectionProperty('core_component', 'plugintypes');
$plugintypes->setValue(null, null);
}
/**
* Test the PSR classloader.
*

View File

@ -35,54 +35,74 @@
<testsuites>
<testsuite name="core_phpunit_testsuite">
<directory suffix="_test.php">lib/phpunit/tests</directory>
<exclude>lib/phpunit/tests/classes</exclude>
</testsuite>
<testsuite name="core_test_testsuite">
<directory suffix="_test.php">lib/testing/tests</directory>
<exclude>lib/testing/tests/classes</exclude>
</testsuite>
<testsuite name="core_ddl_testsuite">
<directory suffix="_test.php">lib/ddl/tests</directory>
<exclude>lib/ddl/tests/classes</exclude>
</testsuite>
<testsuite name="core_dml_testsuite">
<directory suffix="_test.php">lib/dml/tests</directory>
<exclude>lib/dml/tests/classes</exclude>
</testsuite>
<testsuite name="core_testsuite">
<directory suffix="_test.php">lib/tests</directory>
<exclude>lib/tests/classes</exclude>
<!-- <directory suffix="_test.php">lib/ajax/tests</directory> -->
</testsuite>
<testsuite name="core_external_testsuite">
<directory suffix="_test.php">lib/external/tests</directory>
<exclude>lib/external/tests/classes</exclude>
</testsuite>
<testsuite name="core_favourites_testsuite">
<directory suffix="_test.php">favourites/tests</directory>
<exclude>favourites/tests/classes</exclude>
</testsuite>
<testsuite name="core_form_testsuite">
<directory suffix="_test.php">lib/form/tests</directory>
<exclude>lib/form/tests/classes</exclude>
</testsuite>
<testsuite name="core_files_testsuite">
<directory suffix="_test.php">lib/filestorage/tests</directory>
<directory suffix="_test.php">lib/filebrowser/tests</directory>
<directory suffix="_test.php">files/tests</directory>
<exclude>lib/filestorage/tests/classes</exclude>
<exclude>lib/filebrowser/tests/classes</exclude>
<exclude>files/tests/classes</exclude>
</testsuite>
<testsuite name="core_filter_testsuite">
<directory suffix="_test.php">filter/tests</directory>
<exclude>filter/tests/classes</exclude>
</testsuite>
<testsuite name="core_role_testsuite">
<directory suffix="_test.php">admin/roles/tests</directory>
<exclude>admin/roles/tests/classes</exclude>
</testsuite>
<testsuite name="core_cohort_testsuite">
<directory suffix="_test.php">cohort/tests</directory>
<exclude>cohort/tests/classes</exclude>
</testsuite>
<testsuite name="core_grades_testsuite">
<directory suffix="_test.php">lib/grade/tests</directory>
<directory suffix="_test.php">grade/tests</directory>
<directory suffix="_test.php">grade/grading/tests</directory>
<directory suffix="_test.php">grade/import/csv/tests</directory>
<exclude>lib/grade/tests/classes</exclude>
<exclude>grade/tests/classes</exclude>
<exclude>grade/grading/tests/classes</exclude>
<exclude>grade/import/csv/tests/classes</exclude>
</testsuite>
<testsuite name="core_analytics_testsuite">
<directory suffix="_test.php">analytics/tests</directory>
<exclude>analytics/tests/classes</exclude>
</testsuite>
<testsuite name="core_availability_testsuite">
<directory suffix="_test.php">availability/tests</directory>
<exclude>availability/tests/classes</exclude>
</testsuite>
<testsuite name="core_backup_testsuite">
<directory suffix="_test.php">backup/controller/tests</directory>
@ -90,135 +110,185 @@
<directory suffix="_test.php">backup/moodle2/tests</directory>
<directory suffix="_test.php">backup/tests</directory>
<directory suffix="_test.php">backup/util</directory>
<exclude>backup/controller/tests/classes</exclude>
<exclude>backup/converter/moodle1/tests/classes</exclude>
<exclude>backup/moodle2/tests/classes</exclude>
<exclude>backup/tests/classes</exclude>
<exclude>backup/util/classes</exclude>
</testsuite>
<testsuite name="core_badges_testsuite">
<directory suffix="_test.php">badges/tests</directory>
<exclude>badges/tests/classes</exclude>
</testsuite>
<testsuite name="core_blog_testsuite">
<directory suffix="_test.php">blog/tests</directory>
<exclude>blog/tests/classes</exclude>
</testsuite>
<testsuite name="core_customfield_testsuite">
<directory suffix="_test.php">customfield/tests</directory>
<exclude>customfield/tests/classes</exclude>
</testsuite>
<testsuite name="core_iplookup_testsuite">
<directory suffix="_test.php">iplookup/tests</directory>
<exclude>iplookup/tests/classes</exclude>
</testsuite>
<testsuite name="core_course_testsuite">
<directory suffix="_test.php">course/tests</directory>
<exclude>course/tests/classes</exclude>
</testsuite>
<testsuite name="core_courseformat_testsuite">
<directory suffix="_test.php">course/format/tests</directory>
<exclude>course/format/tests/classes</exclude>
</testsuite>
<testsuite name="core_privacy_testsuite">
<directory suffix="_test.php">privacy/tests</directory>
<exclude>privacy/tests/classes</exclude>
</testsuite>
<testsuite name="core_question_testsuite">
<directory suffix="_test.php">question/engine/tests</directory>
<directory suffix="_test.php">question/tests</directory>
<directory suffix="_test.php">question/type/tests</directory>
<directory suffix="_test.php">question/engine/upgrade/tests</directory>
<exclude>question/engine/tests/classes</exclude>
<exclude>question/tests/classes</exclude>
<exclude>question/type/tests/classes</exclude>
<exclude>question/engine/upgrade/tests/classes</exclude>
</testsuite>
<testsuite name="core_cache_testsuite">
<directory suffix="_test.php">cache/tests</directory>
<exclude>cache/tests/classes</exclude>
</testsuite>
<testsuite name="core_calendar_testsuite">
<directory suffix="_test.php">calendar/tests</directory>
<exclude>calendar/tests/classes</exclude>
</testsuite>
<testsuite name="core_enrol_testsuite">
<directory suffix="_test.php">enrol/tests</directory>
<exclude>enrol/tests/classes</exclude>
</testsuite>
<testsuite name="core_group_testsuite">
<directory suffix="_test.php">group/tests</directory>
<exclude>group/tests/classes</exclude>
</testsuite>
<testsuite name="core_message_testsuite">
<directory suffix="_test.php">message/tests</directory>
<exclude>message/tests/classes</exclude>
</testsuite>
<testsuite name="core_notes_testsuite">
<directory suffix="_test.php">notes/tests</directory>
<exclude>notes/tests/classes</exclude>
</testsuite>
<testsuite name="core_tag_testsuite">
<directory suffix="_test.php">tag/tests</directory>
<exclude>tag/tests/classes</exclude>
</testsuite>
<testsuite name="core_rating_testsuite">
<directory suffix="_test.php">rating/tests</directory>
<exclude>rating/tests/classes</exclude>
</testsuite>
<testsuite name="core_repository_testsuite">
<directory suffix="_test.php">repository/tests</directory>
<exclude>repository/tests/classes</exclude>
</testsuite>
<testsuite name="core_userkey_testsuite">
<directory suffix="_test.php">lib/userkey/tests</directory>
<exclude>lib/userkey/tests/classes</exclude>
</testsuite>
<testsuite name="core_user_testsuite">
<directory suffix="_test.php">user/tests</directory>
<exclude>user/tests/classes</exclude>
</testsuite>
<testsuite name="core_webservice_testsuite">
<directory suffix="_test.php">webservice/tests</directory>
<exclude>webservice/tests/classes</exclude>
</testsuite>
<testsuite name="core_mnet_testsuite">
<directory suffix="_test.php">mnet/tests</directory>
<exclude>mnet/tests/classes</exclude>
</testsuite>
<testsuite name="core_completion_testsuite">
<directory suffix="_test.php">completion/tests</directory>
<exclude>completion/tests/classes</exclude>
</testsuite>
<testsuite name="core_comment_testsuite">
<directory suffix="_test.php">comment/tests</directory>
<exclude>comment/tests/classes</exclude>
</testsuite>
<testsuite name="core_search_testsuite">
<directory suffix="_test.php">search/tests</directory>
<exclude>search/tests/classes</exclude>
</testsuite>
<testsuite name="core_competency_testsuite">
<directory suffix="_test.php">competency/tests</directory>
<exclude>competency/tests/classes</exclude>
</testsuite>
<testsuite name="core_my_testsuite">
<directory suffix="_test.php">my/tests</directory>
<exclude>my/tests/classes</exclude>
</testsuite>
<testsuite name="core_auth_testsuite">
<directory suffix="_test.php">auth/tests</directory>
<exclude>auth/tests/classes</exclude>
</testsuite>
<testsuite name="core_block_testsuite">
<directory suffix="_test.php">blocks/tests</directory>
<exclude>blocks/tests/classes</exclude>
</testsuite>
<testsuite name="core_login_testsuite">
<directory suffix="_test.php">login/tests</directory>
<exclude>login/tests/classes</exclude>
</testsuite>
<testsuite name="core_plagiarism_testsuite">
<directory suffix="_test.php">plagiarism/tests</directory>
<exclude>plagiarism/tests/classes</exclude>
</testsuite>
<testsuite name="core_portfolio_testsuite">
<directory suffix="_test.php">portfolio/tests</directory>
<exclude>portfolio/tests/classes</exclude>
</testsuite>
<testsuite name="core_editor_testsuite">
<directory suffix="_test.php">lib/editor/tests</directory>
<exclude>lib/editor/tests/classes</exclude>
</testsuite>
<testsuite name="core_rss_testsuite">
<directory suffix="_test.php">rss/tests</directory>
<exclude>rss/tests/classes</exclude>
</testsuite>
<testsuite name="core_table_testsuite">
<directory suffix="_test.php">lib/table/tests</directory>
<exclude>lib/table/tests/classes</exclude>
</testsuite>
<testsuite name="core_h5p_testsuite">
<directory suffix="_test.php">h5p/tests</directory>
<exclude>h5p/tests/classes</exclude>
</testsuite>
<testsuite name="core_xapi_testsuite">
<directory suffix="_test.php">lib/xapi/tests</directory>
<exclude>lib/xapi/tests/classes</exclude>
</testsuite>
<testsuite name="core_contentbank_testsuite">
<directory suffix="_test.php">contentbank/tests</directory>
<exclude>contentbank/tests/classes</exclude>
</testsuite>
<testsuite name="core_payment_testsuite">
<directory suffix="_test.php">payment/tests</directory>
<exclude>payment/tests/classes</exclude>
</testsuite>
<testsuite name="core_reportbuilder_testsuite">
<directory suffix="_test.php">reportbuilder/tests</directory>
<exclude>reportbuilder/tests/classes</exclude>
</testsuite>
<testsuite name="core_adminpresets_testsuite">
<directory suffix="_test.php">admin/presets/tests</directory>
<exclude>admin/presets/tests/classes</exclude>
</testsuite>
<testsuite name="core_admin_testsuite">
<directory suffix="_test.php">admin/tests</directory>
<exclude>admin/tests/classes</exclude>
</testsuite>
<testsuite name="core_communication_testsuite">
<directory suffix="_test.php">communication/tests</directory>
<exclude>communication/tests/classes</exclude>
</testsuite>
<!--Plugin suites: use admin/tool/phpunit/cli/util.php to build phpunit.xml from