Follow-up to #2722731: Mark MissingDependentModuleUnitTest as incomplete
Follow-up to #2721355: MissingDependentModuleUnitTest has the wrong namespace
Problem/Motivation
This will I assume be expected functionality for feature parity coming from simpletest unit tests. This is related to #1273478: Implement @requires and @dependencies within TestBase, mark tests as skipped but implements the phpunit side only and fulfills the existing @todo in KernelTestBase.
Proposed resolution
Use @requires module modulename
annotation at the class level and also at the test method level.
Disallow TestDiscovery from discarding tests that are annotated in this way.
Tests annotated this way will scan for the module on the filesystem and mark the test as skipped if the module is not present.
Remaining tasks
User interface changes
API changes
Does not change the API, but alters its behavior to make @require dependencies explicit.
Change record: https://www.drupal.org/node/2857979
Data model changes
Comment | File | Size | Author |
---|---|---|---|
#75 | 2728579_75.patch | 18.71 KB | Mile23 |
#69 | interdiff.txt | 8.14 KB | Mile23 |
#69 | 2728579_69.patch | 18.67 KB | Mile23 |
#65 | interdiff.txt | 1.1 KB | Mile23 |
#65 | 2728579_65.patch | 20.14 KB | Mile23 |
Comments
Comment #2
neclimdulPersonally I prefer @requires and its what we reference in an exception in KTB already. Here's an implementation.
Comment #4
neclimdulGot the namespace wrong.
Comment #5
neclimdulreroll after #2721355: MissingDependentModuleUnitTest has the wrong namespace. should be good to go now.
Comment #6
dawehnerIt would be nice to expand this to kernel tests as well. Unit tests don't really make sense I think.
Comment #7
klausiMakes sense! some minor stuff:
Should be "Iterates through a list of requires annotations and looks for missing modules. The test will be skipped if any of the required modules is missing."
type is missing. I assume string[]?
This should have a method comment like "Tests that requires annotation work on methods."
And a long comment after that: "This test method must not be invoked because it requires a not existing Drupal module."
"should be skipped"
@dawehner: this is all about kernel tests? do you mean expanding this to browser tests and javascript browser tests?
Comment #8
neclimdul1) done
2) done
3) stole and modified slightly the line from the other test so it fit in one line.
4) done
Yeah, he we actually cleared that up in IRC but neither of us ever commented here. He did mean BTB and I think the plan is to move the logic to a trait with a helper method that BTB, KTB and what ever else can use in their checkRequirements(). That way each can have unique requirements but also share this functionality. Whether that is done as a follow up or here I don't have strong feelings about I just haven't had time to do either yet.
Comment #9
neclimdulThoughts? This seems pretty important for supporting contrib.
Comment #10
klausiwhy do we have to do this in every loop iteration? Can this be outside of the loop?
there should be a newline after "}".
no sure this is a good idea since you will always have a skipped test in the drupal test suite that you cannot satisfy. I would prefer a test that comes with a test class that is not discovered by phpunit, so that it does not even show up in our test suite.
same problem here, this pollutes our test suite with a skipped test we can never satisfy.
Comment #11
neclimdul1) 2) man I must have been really lazy writing that. definitely thanks.
3) 4) yeah... I don't have a problem with skipped tests honestly but I assume someone is going to want to fail on skips and this would break that. Let me think about how to handle that.
Comment #12
neclimdulComment #13
neclimdulerr... forgot the comments. Test changes: Moved them into a fixtures directory outside the test suites where they won't be found. Manually include them and then assert their exceptions.
Because the skip exception is a special exception that could be handled by phpunit and I didn't want the possibility of silently running into any problems with that at some point int the future I test each exception in a try catch directly.
Comment #14
klausiMakes sense! Minor stuff:
doc comment is missing, like "Tests that a test case is skipped when a "requires" annotation is used."
unused use statements.
doc block is missing indicating that this is not a real test case, so that people are not confused why it is never executed.
Use statement for KernelTestBase is missing.
That line can be removed now that the test method is never actually called.
use statement for KernelTestBase is missing. And should have a description again that this is not a real test class.
Comment #17
Mile23Re-opened #2722731: Mark MissingDependentModuleUnitTest as incomplete with a change.
Comment #18
Mile23The patch in #12 still applies.
It should change
MissingDependentModuleUnitTest
instead of addingMissingDependentModuleTest
. If #2722731: Mark MissingDependentModuleUnitTest as incomplete makes it in first then we'll need a re-roll here. If this issue gets committed first, then the other one is duplicate.Also,
TestDiscovery
looks at@requires
annotation for *all* tests, sorun-tests.sh
will simply not run the tests here. Check the testbot console log for #12 and there's no evidence that either of the tests in the patch ran and were skipped. https://dispatcher.drupalci.org/job/default/162695/consoleFullSo we need to modify
TestDiscovery
so it still ignores Simpletest tests based on@requires
, but not phpunit ones. And eventually remove that entirely in #1273478: Implement @requires and @dependencies within TestBase, mark tests as skippedComment #19
Mile23OK, the skip tests are present and passing... https://dispatcher.drupalci.org/job/default/162695/testReport/PHPUnit/Dr...
:-)
Still, though, we need to modify TestDiscovery because the test bypasses the discovery process.
Here's a patch that addresses #14 and also changes TestDiscovery to ignore @requires for PHPUnit-based tests so they can mark themselves as skipped.
We need a follow-up so that run-tests.sh has a way to report skipped tests, because it currently can't.
Comment #21
Mile23It turns out that if you use the class hierarchy to determine which class belongs to which suite, you fill up memory. For PHP 5.6 at least. PHP 7 is fine.
Also,
getTestInfo()
already got this information for us so we can just use that.Comment #23
dawehnerI'm a bit confused that this is part of kernel tests and not browser test base as well?
Should we maybe split up this test into two parts and then use
$this->setExcpectedException
?Comment #24
Mile23#23.1 will probably require a trait, and some other refactoring.
This patch splits up the test and uses
setExcpectedException()
.Comment #26
dawehnerI guess adding a follow up would be worth doing maybe?
Comment #27
Mile23Added follow-up: #2857977: Support @require module in BrowserTestBase tests
Added change record: https://www.drupal.org/node/2857979
Fixed the failing test... It turns out you have to call setName() in order to tell the test class what method you're dealing with. Then it will pick up the annotations from that method. @neclimdul had done that, and I broke it. Ewps.
Comment #28
klausithis should be as close to the call where the exception will occur as possible. Which means right before the last line.
same here.
Otherwise looks good!
Comment #29
Mile23OK. :-)
Comment #30
klausiCool, thanks!
Comment #31
alexpottI don't get why #2857977: Support @require module in BrowserTestBase tests is not in scope for this issue - it feels more important that KernelTestBase test. Plus if we're going to use traits or whatever - why not get that right first time?
I don't get why we are deleting this test. As far as I can see we should be leaving it alone until we completely remove all simpletest.
Comment #32
klausiI'd rather like to get stuff done in smaller chunks - but sure, we can also fold #2857977: Support @require module in BrowserTestBase tests into this issue.
MissingDependentModuleUnitTest is removed because:
a) it is not a unit test
b) is a browser test, not a web test.
c) it is not simpletest specific, so should not be in simpletest module
A trait makes sense to be shared between kernel tests and browser tests. Name? CheckRequirementsTrait? TestRequirementsTrait?
Comment #33
alexpottAh I see about MissingDependentModuleUnitTest - but what this means is that we are missing test coverage of the simpletest code path. Before this change we had test coverage - because all test types when run through run-tests.sh are using the same code - now they are not. So we need to add a simpletest to ensure we are not breaking the legacy code path.
TestRequirementsTrait sounds good.
Comment #34
alexpottAlso re the BTB being in scope - at the moment it works for them - as the existing test proves when run through run-tests.sh - if we don't include it here then we break it.
Comment #35
Mile23BTB behavior was a follow-up because it's easier to write a follow-up than the trait, unless there's sign-off that work should continue on this issue. And now there is.
MissingDependentModuleUnitTest
is removed because it can't pass, only fail, isn't very informative. And now it’s replaced by unit tests ofTestRequirementsTrait::checkRequirements()
.Well, no. We didn't start with coverage of the simpletest path. There are a bunch of linked issues at the top about which test base it should inherit from, with not a lot of consensus, because it's a bad test.
MissingDependentModuleUnitTest
inherits fromDrupal\Tests\BrowserTestBase
and only signals thatTestDiscovery
should check for dependencies using@requires
. Simpletest uses@dependencies
(which is converted to a 'requires' array bygetTestInfo()
.)We don’t want the
TestDiscovery
path to be testable in this way by aBrowserTestBase
test after this issue.This patch adds a Simpletest based test called
\Drupal\simpletest\Tests\SkipRequiredModulesTest
that performs this test. Note that it's either skipped or fails based on how it's discovered by run-tests.sh: --class and --file ignore the @dependencies annotation. This will be OK after #1273478: Implement @requires and @dependencies within TestBase, mark tests as skipped but not before.By the end of this issue and #1273478: Implement @requires and @dependencies within TestBase, mark tests as skipped,
run-tests.sh
(reallyTestDiscovery
) won't have an opinion about which type of test it's running, WRT@requires module
. It'd be great to haverun-tests.sh
be properly maintainable and testable, so that we could test the old vs. new behavior, but since it’s not, we don’t.Comment #36
Mile23Comment #37
Mile23Comment #38
klausiLooks good, just super minor stuff:
@inheritdoc does not really work on traits, I think we just need to copy the docs, right?
KernelTestBase is in the same namespace, so this use statement is not needed. Also elsewhere. And the coding standards check of the last testrun even detected that, yipee!
Comment #39
Mile23Yes, very helpful. :-) Added more helpful docs.
Addressed all the things.
Thanks. :-)
Comment #40
Mile23Found this while fixing that last patch: #2861376: ToolkitGdTest uses checkRequirements() incorrectly
Updated change record: https://www.drupal.org/node/2857979
Comment #41
neclimdulWait why do we care about this?
Comment #42
Mile23We care about it because we're going to make it go away in #1273478: Implement @requires and @dependencies within TestBase, mark tests as skipped
Simpletest tests don't skip themselves on @requires; they're only skipped on discovery, as if they had never been discovered.
Comment #43
Munavijayalakshmi CreditAttribution: Munavijayalakshmi at Valuebound commentedComments do not require a new line until they reach 80 characters.
Fixed and attached new patch.
Comment #44
klausiThanks, everything looking good!
Comment #46
Mile23Restarting test.
Comment #47
dawehnerI'd have used the same module name here, but more important, use "does_not_exist" or so. DNE is a an appr. which makes it harder to read than it would have to be.
Comment #48
Mile23TLA WTF. (Three-Letter Acronym.)
Also some incorrect docblocks.
Also this needs a follow-up to decide on what group these tests belong to. BTBTest belongs to @group browsertestbase and KTBTest belongs to @group PHPUnit, so basically we can't say 'run all tests about tests' using a group. See also: #2296615: Accurately support multiple @groups per test class
Comment #49
Mile23Follow-up: #2864840: Adopt consistent naming standards for multiple test @groups
Comment #50
klausiNice improvements!
just realized that this test should not be on BrowserTestBaseTest. It does not use a browser, so this should be a unit or kernel test instead, right?
Comment #51
Mile23If the BTB versions of these stub test classes were run under a KTB-based test, then we'd have the following problem:
SIMPLETEST_DB=mysql://thingie ./vendor/bin/phpunit -c core/ --testsuite kernel
would attempt to run BTB tests, which would break.Comment #52
klausiLooked into this, your additions to BrowserTestBaseTest do not test what you think:
So the test is skipped instead of being fully executed.
So we can't use setExpectedException() for those tests. I tried out this unit test which works:
So there is no reason to do this in BrowserTestBaseTest which is just slow.
minor performance complaint: we should check first if there even is "module " in one of the annoations and only then do the scanning.
Also should we statically cache the scanned module $list once? Not sure how good ExtensionDiscovery already caches stuff.
Comment #53
Mile23Comment #54
klausiInteresting, but we can fix that by either doing
require_once $root . '/core/includes/bootstrap.inc';
in DrupalKernelTest or defining drupal_valid_test_ua() in the same hacky way in our unit test, right?Comment #55
Mile23Or, you know... Keeping suite isolation as per #51. :-)
Comment #56
klausiI think the fact that this is a unit test trumps suite isolation. I agree with catch in #2770549: [plan] Discuss desired API and test suite following deprecation of SimpleTest that a browser test should ideally not invoke any APIs at all and just use the browser. We are really doing a unit test here of our browser testing framework which itself is not a browser test.
Comment #57
Mile23OK, so the requirements check for
BrowserTestBase
works as a kernel test, even though it should actually be a unit test as @klausi points out.The reason it can't be a unit test is because
DrupalKernelTest
defines a global function when it shouldn't, because it's a bad unit test. The various solutions to that problem are out of scope here so we'll just have a kernel test.This patch avoids using
BrowserTestBase
to test anything, and also does some optimization on the required module discovery per #52.Comment #59
Mile23Neglected to change back
TestInfoParsingTest
after revertingBrowserTestBaseTest
.Comment #60
Mile23Patch still applies. Re-running -test.
Comment #62
Dane Powell CreditAttribution: Dane Powell at Acquia commentedUpdated title to reflect "requires" instead of "require"
Comment #63
Mile23Reroll.
Comment #65
Mile23Removed @covers annotation, since this is a functional test and doesn't cover code.
Comment #66
dawehnerCould this test class make checkRequirements public by default? I think this would be a little bit simpler
Is there a reason we don't use
setExpectedException
?Comment #67
Mile231) checkRequirements() is protected because its parent is protected: https://github.com/sebastianbergmann/phpunit/blob/master/src/Framework/T...
2)
If the module requirement isn't found, we throw a skipped test exception. PHPUnit handles the exception to skip the whole test before it evaluates any expected exceptions, so the test never passes or fails. We solve this with a try block.
Comment #68
dawehnerOh well, i was thinking making it public in the test class itself, but just there, so you don't have to do the reflection dance.
Comment #69
Mile23So as I sit and look at the last patch I keep asking myself: Why are there two tests for
BrowserTestBase
? And the answer is: I never finished. :-)That's why the interdiff is bigger than it should be.
This patch properly tests both
BrowserTestBase
andKernelTestBase
, both as kernel tests.It also adds public accessors to the fixture test classes, so we can avoid doing the reflection thing as per #68.
Comment #70
dawehnerha, I was wondering, do you maybe need some special setup, which is provided by BTB by default, but it turns out nope :)
Thank you for having an explanation.
Comment #73
Mile23I can't repro the test fail locally, for either 8.4.x or 8.5.x: https://www.drupal.org/pift-ci-job/728283
I'd argue that this is a good candidate for 8.4.0 release, since it's a testing improvement, but it's also somewhat disruptive in that tests will be marked as skipped instead of just ignored by
TestDiscovery
. Whether that's too disruptive is obviously for maintainers to decide. Setting back to 8.4.x.It's also not an API change, really. It just changes the behavior of the existing API to give more information to users.
Re-running the test, resetting RTBC.
Updating change record: https://www.drupal.org/node/2857979
Comment #74
catchNeeds a re-roll.
Comment #75
Mile23Rerolled.
Comment #76
neclimdulstill looks good to me so back to rtbc.
Comment #77
Wim LeersHas CR, that clearly explains the improvement 👍
Supernit: s/use-case/use case/
❤️ Love the explicit comment!
I'd have thought this would be called
browserMissingDependentModuleClassTest
, but that's nitpicking.I'd have thought this would be called
KernelMissingDependentModuleClassTest
, but that's nitpicking.Comment #79
catchCommitted/pushed to 8.5.x and cherry-picked to 8.4.x. Thanks!
Comment #82
rodrigoaguileraWhy the change record is not published?
I arrived to this issue because I'm dealing with a test that is not skipped despite having the annotation.
I think we need to wait for this bug to be fixed before publishing it.
#3261817: TestRequirementsTrait::checkRequirements() does not work as expected
Comment #83
quietone CreditAttribution: quietone at PreviousNext commentedpublish the change record