The @backupStaticAttributes
and @backupGlobals
attributes should not be used in pure unit tests.
Unit tests should explicitly manage the state of global and static variables under test.
The two features are only meant for functional/integration testing (as well as testing legacy code bases), but not for pure unit tests. Especially the behavior of @backupStaticAttributes
is hard to predict and not documented yet - which is documented now.
$ grep -r --include='*Test.php' --exclude-dir=vendor '@backup' core core/tests/Drupal/Tests/Core/Form/FormCacheTest.php: * @backupStaticAttributes enabled
Task
-
Figure out what statics need to be reset in affected test(s).
-
Reset them both in
setUp()
andtearDown()
.
The fact that the global state dependencies of affected tests are unknown further underlines why the @backup*
features should not be used in (pure) unit tests.
Comment | File | Size | Author |
---|---|---|---|
#1 | phpunit-2329765-1.patch | 1.49 KB | tim.plunkett |
Comments
Comment #1
tim.plunkettThe usage of it in FormCacheTest is not "unknown". It's for SafeMarkup, which has (and needs) no way to reset the seen IDs.
Comment #2
sunThanks! I did hope that you'd remember why
@backupStaticAttributes
is used in that recently added test. :)I don't know why
SafeMarkup
needs a static like that and why it can't use a stack/collection object, but it's good that the issue is exposed now.PHPUnit's documentation has been clarified; the improvements will be deployed in the next days.
Comment #3
sunFWIW,
run-tests.sh
and the testbot do not reveal such leaking global state currently, because unit tests are effectively executed as if--process-isolation
was used for PHPUnit (which is terribly slow and thus strongly not recommended).Process isolation means that every test (class, in case of run-tests.sh) is executed in a separate process. When reloaded from scratch in a separate process, static class properties do have their originally declared default values.
However, process isolation is only meant to be used for legacy code that cannot be refactored/tested through other means, or for testing internal PHP constructs that cannot be isolated at all (such as testing a class loader).
Regular unit tests should not use or depend on process isolation. The current execution of unit tests in
run-tests.sh
is a straight bug, caused by its legacy architecture. That difference results in test errors when runningphpunit
from the command line (which intentionally does not use process isolation by default).The 12 errors that are currently reported by
phpunit
are a testament to that:The errors are caused by
@backupStaticAttributes
, because it tries to serialize every value of every static property in each and every class that happens to be declared.__sleep()
function somewhere in our code, but that's a separate issue, unrelated to this issue here.run-tests.sh
, my goal is to get rid of it entirely for 8.0.0.Comment #4
sunComment #5
neclimdulYeah, legacy and incremental design added to tight coupling to the web runner which is effectively our first class runner. I never considered removing the script because I find being able to somewhat replicate the testbots locally is useful but I have toyed with it several times. Not breaking the webrunner in the process has always tripped me up so I'm interested in your plans.
Anyways, big +1 and RTBC again if that's possible. Soon if possible because running tests in PhpStorm is annoying with these failures.
Comment #6
webchickNo idea what this does, but I guess it's safe if sun and tim agree. :)
Committed and pushed to 8.x. Thanks!