Problem/Motivation

Trying to run tests with PHPUnit results in this error:

[08-Mar-2020 04:03:27 Australia/Sydney] PHP Fatal error:  Cannot declare class Drupal\Tests\Core\Theme\TestRegistry, because the name is already in use in /Users/paul/projects/drupal/core/tests/Drupal/Tests/Core/Theme/RegistryTest.php on line 493

This is because Drupal\Tests\Core\Theme\RegistryTest and Drupal\Tests\Core\Theme\RegistryLegacyTest both define a class called Drupal\Tests\Core\Theme\TestRegistry, and they're both declared during test discovery.

This error does not happen during run-tests.sh because Drupal's bespoke test discovery system does not load classes.

Proposed resolution

Use mock objects to meet the needs of the tests.

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Mile23 created an issue. See original summary.

Mile23’s picture

Have a patch.

I'm pretty sure we should nuke get_defined_functions() as well, but the tests run without error without removing it, so there we are.

Mile23’s picture

Status: Active » Needs review
Mile23’s picture

Issue summary: View changes
FileSize
4.02 KB
628 bytes

I spoke too soon.

[08-Mar-2020 04:38:53 Australia/Sydney] PHP Fatal error:  Cannot redeclare Drupal\Core\Theme\get_defined_functions() (previously declared in /Users/paul/projects/drupal/core/tests/Drupal/Tests/Core/Theme/RegistryLegacyTest.php:179) in /Users/paul/projects/drupal/core/tests/Drupal/Tests/Core/Theme/RegistryTest.php on line 504

Only RegistryTest needs get_defined_functions(), so we can just delete it from RegistryLegacyTest, kicking the can into the future. :-)

mondrake’s picture

Priority: Normal » Critical
FileSize
1 KB

Since the issue of PHPUnit CLI testing breaking is recurring quite frequently, I thought it would be good to add a test to prevent regressions. The problem is that DrupalCI, through run-tests.sh, runs tests one at a time indicating a test file at each run. That prevents PHPUnit's own test discovery mechanism to execute. However, that is exactly the mechanism that runs at the time of testing through CLI (which we are recommending more and more over run-tests.sh, btw), and that mechanisms autoload classes across different files - and that's when collisions happen.

The test here is inspired by BuildTestBase.

Mile23’s picture

Generally +1 on exercising the cli. I'd suggest that we can do the test discovery part without the test running part by calling phpunit -c core --list-tests. Also it could be a build test which has handy assertions for processes already.

Status: Needs review » Needs work

The last submitted patch, 5: 3118477-5-test-only.patch, failed testing. View results

mondrake’s picture

Status: Needs work » Needs review
FileSize
5.02 KB
1 KB
743 bytes

#6:

I'd suggest that we can do the test discovery part without the test running part by calling phpunit -c core --list-tests

Done that.

it could be a build test

I tried that but failed to make it work... anyone feel free to take it on if you deem it relevant.

mondrake’s picture

mondrake’s picture

Version: 8.9.x-dev » 9.0.x-dev
mondrake’s picture

alexpott’s picture

+++ b/core/tests/Drupal/Tests/Core/Test/PhpUnitCliTest.php
@@ -0,0 +1,29 @@
+/**
+ * @group Test
+ */
+class PhpUnitCliTest extends UnitTestCase {
+
+  /**
+   * Tests that running tests via the PHPUnit CLI works properly.
+   */
+  public function testPhpUnitCliRun() {
+    $process = new Process('vendor/bin/phpunit --configuration core --verbose --list-tests');
+    $process->setWorkingDirectory($this->root)
+      ->setTimeout(300)
+      ->setIdleTimeout(300);
+    $process->run();
+    $this->assertEquals(0, $process->getExitCode(),
+      'COMMAND: ' . $process->getCommandLine() . "\n" .
+      'OUTPUT: ' . $process->getOutput() . "\n" .
+      'ERROR: ' . $process->getErrorOutput() . "\n"
+    );
+  }
+
+}

I don't think this is the right approach. Running all our unit tests again to prove that they are all runnable as one feels way off. Either we do that or we do tun-tests.sh but doing both feels very Drupal.

Also why is this a critical task. If running a single PHPUnit test from the command line was broken I'd agree but it is not. This are only broken when you run core/tests/Drupal/Tests/Core/Theme/RegistryLegacyTest.php and core/tests/Drupal/Tests/Core/Theme/RegistryTest.php in the same PHPUnit run.

mondrake’s picture

Priority: Critical » Major
Parent issue: » #3109480: Properly deprecate theme functions for Drupal 10

#12 with --list-tests we just discover the tests, without running them. Test discovery is enough to autoload all test classes by PHPUnit CLI and show the problem.

why is this a critical task

right - major given Cause test failures in environments not supported by the automated testing platform. in Priority levels of issues.

Anyway, this comes from #3109480: Properly deprecate theme functions for Drupal 10 which is a committed critical, half way being backported to 8.x.

catch’s picture

+++ b/core/tests/Drupal/Tests/Core/Test/PhpUnitCliTest.php
@@ -0,0 +1,29 @@
+
+  /**
+   * Tests that running tests via the PHPUnit CLI works properly.
+   */
+  public function testPhpUnitCliRun() {
+    $process = new Process('vendor/bin/phpunit --configuration core --verbose --list-tests');
+    $process->setWorkingDirectory($this->root)
+      ->setTimeout(300)
+      ->setIdleTimeout(300);
+    $process->run();
+    $this->assertEquals(0, $process->getExitCode(),
+      'COMMAND: ' . $process->getCommandLine() . "\n" .
+      'OUTPUT: ' . $process->getOutput() . "\n" .
+      'ERROR: ' . $process->getErrorOutput() . "\n"
+    );
+  }
+

I don't think this is helpful as a core test, it is extremely meta. If we really want to add this as a linting thing, we could add it to DrupalCI itself?

The last submitted patch, 11: 3118477-10-test-only.patch, failed testing. View results

Mile23’s picture

Yesterday I was going to work on this composer initiative issue: #3047468: Create a tool to convert a non-Composer-based Drupal to a Composer-based one But instead I worked on this blocker issue because there's only so much time in the day. It's a blocker in that I can't run tests, and I run a lot of tests when I work.

#3109480: Properly deprecate theme functions for Drupal 10 introduced a regression, and so therefore we should test to make sure we don't re-introduce a similar regression in the future. We've had plenty of these in the past. Keep in mind, folks: We have mocking frameworks for a reason. :-)

If there's a better way to prevent this regression than exercising the test suites, then let's do that. But for now, here's basically the same patch with some nicer docs.

@mondrake is right and turning the test into a build test would involve calling copyCodebase(), which would add a bunch of file copies to the run time of this test, so let's not do that.

neclimdul’s picture

Status: Needs review » Reviewed & tested by the community
+++ b/core/tests/Drupal/Tests/Core/Test/PhpUnitCliTest.php
@@ -0,0 +1,35 @@
+class PhpUnitCliTest extends UnitTestCase {

You're my hero...Not the prettiest or most complete test but that covers a solid basic lint that will be very helpful and a complete test would be using the runner so yeah... :)

@catch I'd love for DrupalCI to do phpunit testing but after like 5 years of my CI being randomly broken and pushing for using the phpunit runner in testing discussions with no movement.. for things like this I'd love to have at least this basic test. The right fix is such a big lift and this is small and should save a lot of headaches from a class of bugs.

This fixes things so I can run tests and coverage for core issues again, avoids regressions, and passes so RTBC imho.

longwave’s picture

+++ b/core/tests/Drupal/Tests/Core/Theme/RegistryLegacyTest.php
@@ -152,29 +152,18 @@ public function testGetLegacyThemeFunctionRegistryForModule() {
-  return RegistryLegacyTest::$functions ?: \get_defined_functions();

As we are removing this I think we can get rid of all references to $functions in the RegistryLegacyTest class as well.

+1 to adding PhpUnitCliTest to avoid this sort of copy paste error in the future, this was my fault originally so apologies for that :)

alexpott’s picture

Version: 9.0.x-dev » 8.9.x-dev
Status: Reviewed & tested by the community » Fixed

I'm not a huge fan of the test. Because I fear that it'll add noise to the test runs doing double fails. But as it is only listing tests I guess it is better than nothing. I dunno I guess time will tell.

Committed and pushed 0a65cd6076 to 9.0.x and ad2edda33d to 8.9.x. Thanks!

I cleaned up $functions in the legacy test as this change removes its purpose.

diff --git a/core/tests/Drupal/Tests/Core/Theme/RegistryLegacyTest.php b/core/tests/Drupal/Tests/Core/Theme/RegistryLegacyTest.php
index e8a261b4a9..6e00b48440 100644
--- a/core/tests/Drupal/Tests/Core/Theme/RegistryLegacyTest.php
+++ b/core/tests/Drupal/Tests/Core/Theme/RegistryLegacyTest.php
@@ -69,13 +69,6 @@ class RegistryLegacyTest extends UnitTestCase {
    */
   protected $themeManager;
 
-  /**
-   * The list of functions that get_defined_functions() should provide.
-   *
-   * @var array
-   */
-  public static $functions = [];
-
   /**
    * {@inheritdoc}
    */
@@ -92,14 +85,6 @@ protected function setUp() {
     $this->setupTheme();
   }
 
-  /**
-   * {@inheritdoc}
-   */
-  protected function tearDown() {
-    parent::tearDown();
-    static::$functions = [];
-  }
-
   /**
    * Tests getting legacy theme function registry data defined by a module.
    *

Run the test locally - it's fine.

I also fixed the following coding standards:

FILE: ...lt.dev/core/tests/Drupal/Tests/Core/Theme/RegistryLegacyTest.php
----------------------------------------------------------------------
FOUND 2 ERRORS AFFECTING 2 LINES
----------------------------------------------------------------------
   3 | ERROR | [x] Namespaced classes, interfaces and traits should
     |       |     not begin with a file doc comment
 146 | ERROR | [x] Expected 1 space after FUNCTION keyword; 0 found
----------------------------------------------------------------------
PHPCBF CAN FIX THE 2 MARKED SNIFF VIOLATIONS AUTOMATICALLY
----------------------------------------------------------------------

Time: 71ms; Memory: 8MB


FILE: ...upal8alt.dev/core/tests/Drupal/Tests/Core/Theme/RegistryTest.php
----------------------------------------------------------------------
FOUND 2 ERRORS AFFECTING 2 LINES
----------------------------------------------------------------------
   3 | ERROR | [x] Namespaced classes, interfaces and traits should
     |       |     not begin with a file doc comment
 485 | ERROR | [x] Expected 1 space after FUNCTION keyword; 0 found
----------------------------------------------------------------------
PHPCBF CAN FIX THE 2 MARKED SNIFF VIOLATIONS AUTOMATICALLY
----------------------------------------------------------------------

  • alexpott committed 0a65cd6 on 9.0.x
    Issue #3118477 by mondrake, Mile23: RegistryTest, RegistryLegacyTest...

  • alexpott committed ad2edda on 8.9.x
    Issue #3118477 by mondrake, Mile23: RegistryTest, RegistryLegacyTest...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.