Problem/Motivation
Originally in this issue, trying to make a PHPUnit coverage report, PHPUnit complained. Some fixes were started here, but in the meantime, #2358657: Wrong @covers definitions in Drupal project did the fixes necessary to get the coverage report to run.
While working on this issue, a bug: #2364467: SpecialAttributesRouteSubscriber::onAlterRoutes() doesn't return a value was found.
This issue makes the coverage report more accurate.
Allowed in beta?
https://www.drupal.org/core/beta-changes
This is a bug, because some of the @covers are wrong or missing, and the coverage report is misleading (wrong).
This is normal, because it effects just one system (phpunit, specifically coverage information).
This is allowed in the beta, since this effects only automatic tests, and that type of change is unfrozen.
Proposed resolution
make @covers more accurate, using --strict as a guideline, and correct the name of a data provider (so it doesn't appear as a test)
Remaining tasks
(done) Fix stuff.
(done) Fix more stuff.
(done) Rescope issue.
Commit changes.
User interface changes
No.
API changes
No.
| Comment | File | Size | Author |
|---|---|---|---|
| #26 | interdiff.txt | 1.56 KB | mile23 |
| #26 | 2364555_26.patch | 15.44 KB | mile23 |
| #23 | 2364555_23.patch | 14.68 KB | mile23 |
| #17 | 2364555_17.patch | 10.33 KB | mile23 |
| #15 | interdiff.txt | 2.15 KB | mile23 |
Comments
Comment #1
mile23Here's a patch.
Most controversial:
CacheTest::testInvalidateTags()actually testeddeleteTags(), probably due to copypasta fromtestDeleteTags()Removes @covers for non-existent methods, adds @covers in a few files I was touching anyway.
Added assertions to test methods without them (where --strict complained).
Comment #2
mile23Comment #3
yesct commentedah, this is the "controversial" thing you mentioned.
this looks out of scope.
the rest of this looks ok to me (but I didn't run the coverage to see the diff in complaints before and after the patch)
Comment #4
mile23Yah, item 1 I mentioned in comment 1. Item 2 is coding standards, just a comma. if it's a comma too far I can take it out.
Comment #5
mile23Ya know... we *could* make the testbot do that for us. :-)
Comment #6
yesct commentedI commented on #2340123: Setting cache tags can be tricky: use strings instead of nested arrays to improve DX
Comment #7
mile23Here it is without the Cache::invalidateTags() change. I'll move that to the other issue.
Comment #8
mile23See also: #2366645: Drupal\Tests\Core\Controller\AjaxControllerTest has wrong @covers.
Comment #9
tim.plunkettHere's another #2366663: ContextHandlerTest misuses @covers
Comment #10
yesct commentedthis is a great issue. thanks for filing it. and for working on fixing it.
@tim.plunkett yeah, this patch takes care of that.
I have some questions and feedback (and I documented how I tested/reviewed it).
1
./vendor/phpunit/phpunit/phpunit --filter=ResponsiveImageMappingConfigEntityUnitTest --coverage-html /tmp/report
in head, without this patch:
.Trying to @cover or @use not existing method "\Drupal\responsive_image\Entity\ResponsiveImageMapping::hasMapping".with the patch:
2
./vendor/phpunit/phpunit/phpunit --filter=PermissionHandlerTest --coverage-html /tmp/report
before: Trying to @cover or @use not existing method "\Drupal\user\PermissionHandler::buildPermissions".
after: finishes
I dont think there ever was a buildPermissions in PermissionsHandler (there is one in NodePermissions).
3.
./vendor/phpunit/phpunit/phpunit --filter=CacheTest --coverage-html /tmp/report
before: Trying to @cover or @use not existing class or interface "validateTags".
after: finishes
phpstorm complains that a void menthod is having it's result used.
but asserting something seems better than relying on not an exception.
the other changes in here are good (adding :: to before the method name in the @covers line). I also checked the test actually covered it, and they do.
4.
./vendor/phpunit/phpunit/phpunit --filter=DrupalTest --coverage-html /tmp/report
before: Trying to @cover or @use not existing method "::requestStack"
after:
checked this is adding the correct default class.
checked each test, and it does call the method specified by the additional @covers
only the ::l one looked strange, cause it didn't match the oneline summary which said _l() (but I think that summary is wrong, it is called l() )
5.
we might be able to say in this issue to take out these one line summaries.. *but* the working group https://www.drupal.org/governance/technical-working-group has not actually set the standard for our phpunit docs #2057905: [policy, no patch] Discuss the standards for phpunit based tests, so might as well leave these in.
6.
6a.
is out of scope.
6b.
this might be out of scope also.. is it needed to get the --strict to run?
6c.
./vendor/phpunit/phpunit/phpunit --filter=BaseFieldDefinitionTest --coverage-html /tmp/report
before:
(this time it does run)
after:
so then I tried running with --strict:
./vendor/phpunit/phpunit/phpunit --filter=BaseFieldDefinitionTest --strict --coverage-html /tmp/report2
before:
after:
6d. same number of risky tests.
hm. but only 2 more assertions. odd because patch adds asserts (assertNotNull) to 3 tests that did not have any asserts. 3. does something similar. and the results of the code coverage (even with --strict) before and after are the same... so maybe these added assertNotNull() are out of scope also?
7.
fixes @covers
but also adds assertNotNull() to add assert to tests.
./vendor/phpunit/phpunit/phpunit --filter=SqlContentEntityStorageSchemaTest --coverage-html /tmp/report
before: Trying to @cover or @use not existing method "\Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema::getSchema".
after:
8.
./vendor/phpunit/phpunit/phpunit --filter=ContextHandlerTest --coverage-html /tmp/report
before: Trying to @cover or @use not existing method "\Drupal\Core\Plugin\Context\ContextHandler::__construct".
after: finishes
(yeah, and I think setUp() should not @cover anything?)
9.
./vendor/phpunit/phpunit/phpunit --filter=DefaultPluginManagerTest --coverage-html /tmp/report
before: .......Trying to @cover or @use not existing method "\Drupal\Core\Plugin\DefaultPluginManager::enforcePluginInterface".
after: finishes
ok. removes a wrong @covers.
but also adds asserts for two tests that did not have asserts.
10.
./vendor/phpunit/phpunit/phpunit --filter=AccessAwareRouterTest --coverage-html /tmp/report
before ..Trying to @cover or @use not existing method "\Drupal\Core\Routing\Router::__call".
after finishes
this makes sense here, the change in the default covers class
11.
./vendor/phpunit/phpunit/phpunit --filter=ReverseProxyMiddlewareTest --coverage-html /tmp/report
before: OK (4 tests, 6 assertions)
after: OK (3 tests, 6 assertions)
yeah, the naming of the data provider method should not start with test.
and that is why there is 1 less test (and the same number of assertions, cause there are no assertions in a provider)
(but I dont know if --strict caught that for you...)
trying
./vendor/phpunit/phpunit/phpunit --filter=ReverseProxyMiddlewareTest --strict --coverage-html /tmp/report
before:
after:
yeah, this time I can see a change in the risky test numbers using --strict, so this looks in scope.
Comment #11
mile23Thanks for the review.
Re: item 3 and 6d
So a test is risky if it doesn't have an assertion (and doesn't have an expected exception, and doesn't have an
->expects()mock method). It's also just better form to explicitly state your assertion, so the next person can see what you were actually testing. There are probably better ways to write tests of methods that return NULL, but I erred on the side of preserving the test the way it is and just adding a reasonable assertion.As far as assertNotNull(), I added that so they're not risky. A real test would be to assert that the returned object was of a specific class or interface, but since these are existing tests I just want them to not be risky.
6a and b: Both are coding standards issues.
8:
True. And also, we need to move away from the
$this->classUnderTestWhichIsNotIsolatedFromOtherTests->methodToTest()-in-setup() pattern inherited from SimpleTest, but that's ouside this issue. :-)11:
You got it. Adding
--strictto the testbot setup is highly contentious for some reason that baffles me, so instead of having it catch errors like this one and burp back a testbot fail, I'm writing this catch-up issue and you're reviewing it.So here's another patch, removing the coding standards changes in 6a and 6b.
Comment #12
mile23And what the heck. Here's one with assertInstanceOf() instead of assertNotNull(), in circumstances like this:
...in order to be a more specific test.
Comment #13
yesct commentedI dont see how the changes 6c
effect the output of
./vendor/phpunit/phpunit/phpunit --filter=BaseFieldDefinitionTest --strict --coverage-html /tmp/report2
it passes strict before (I think the OK means it passes), and the results of the number of risky tests are the same: 16.
Is there something else we need to do here to make them not risky?
Or are the asserts part of moving them toward not being risky?
Comment #14
mile23Well you'll recall the goal was to make a coverage report. :-)
Combining --strict and --coverage-[anything] apparently turns on a super-strict mode for coverage, where any method call not explicitly @covered or @used gets flagged as risky.
In truth, it *is* risky, because it's not in isolation, so we can't really unit test it. If we're not really unit testing that's fine, but in this case we're trying to.
So if you apply the patch and then do
./vendor/bin/phpunit --strict --coverage-text -v(note the -v), you'll see a bunch of output about which methods are called without being @covered or @used. They're the ones used byBaseFieldDefinitionTest::setUp()to create the fixture and set the\Drupalcontainer.A superficial fix would be to mark all those methods as @used in setUp(). A better and less superficial fix would be to refactor setUp() as a fixture-generating method called by test methods, with @uses annotated on the test method. The best solution of all would be to remove
\Drupalfrom Drupal and do proper dependency injection everywhere. :-)And of course, the most superficial fix of all is to never use
--strictwith--coverage-text.Basically, Drupal unit tests don't come with a lot of discipline. So which is the best solution?
Comment #15
mile23Here's another one.
Fixed the
_l()docs. I think it's probably best policy to leave documentation where possible, and if someone wants to tackle removing the summary lines they can start another issue about it.Made the
BaseFieldDefinitionTestassertions more specific.There's also a larger issue with
DefaultPluginManagerTestbecause it's testing::createInstance(), which it inherits but doesn't implement. That test should really be testingDrupal\Component\Plugin\PluginManagerBase. But again, that's out of the scope of this issue.Comment #16
mile23Added an issue about the
PluginManagerBaseissue mentioned above: #2371531: Expand unit testing for Drupal\Component\Plugin\PluginManagerBaseI think we should keep the tests from
DefaultPluginManagerTest(patched, of course...), as well as the new tests from the new issue.Comment #17
mile23Re-scoping this issue so people can read it, understand it, and RTBC it. :-)
This patch contains only changes from the previous patch which deal with @covers exclusively. So files which had code changes are excluded.
This means it's easy to just see that they're @covers issues. I will file other issues with the other classes previously touched on here.
Comment #18
mile23Comment #19
mile23OK.... I'm marking this issue as postponed to concentrate efforts on this overlapping issue: #2358657: Wrong @covers definitions in Drupal project. Will re-open after that drops.
Comment #20
geerlingguy commentedTo jump in on #19; I'd love to see #2358657: Wrong @covers definitions in Drupal project go in soon so my automated tests/coverage report graphs can have joy and happiness again—they have been empty for some time now :(
Comment #21
geerlingguy commented#2358657: Wrong @covers definitions in Drupal project is fixed, reopening this issue.
Also, is #2287385: Fix PHPUnit coverage tests related to this issue?
Comment #22
mile23I don't think that one is related.
But you might draw your attention to another issue while I reroll this one: #2328919: Remove () from a bunch of @covers definitions in PHPUnit
Comment #23
mile23OK....
Undo the scope change from #17, because the superficial
@coverschanges happened in #2358657: Wrong @covers definitions in Drupal project.This patch is a re-roll of #15.
It adds assertions in many places where there are none.
It adds @covers annotation and very minor docblock corrections to DrupalTest.php, which tests \Drupal.
And it fixes a data provider mis-name in ReverseProxyMiddlewareTest.php. The data provider method started with 'test*', so PHPUnit tried to run it as a test.
Comment #24
yesct commentedsimilar to the rationale for fixing the _l() comment, we should fix this since there is no typedData() method.
I looked at
https://phpunit.de/manual/current/en/appendixes.assertions.html#appendix...
to check if it fails if it gets NULL, but it didn't say there.
Comment #25
yesct commentedshould we add a @covers for onFieldStorageDefinitionCreate ?
Comment #26
mile23#24.1: Good catch.
#24.2: NULL is a type. :-) But also, yah,
assertInternalTypewill barf if it's not an array.#25: Since I've decided these tests are asserting the result of
onFieldStorageDefinitionCreate(), then yes. If I'm wrong, then no. But I'm pretty sure I'm right.However, here's the entire source code for onFieldStorageDefinitionCreate():
performFieldSchemaOperation()doesn't call the other methods annotated as@coveredin those two tests, and all the other dependencies are fully mocked. So therefore: Remove the other@coversannotations. :-) This will probably cause a need for a reroll on #2328919: Remove () from a bunch of @covers definitions in PHPUnit.Really, there should be a unit test for
performFieldSchemaOperation(), because there isn't. That's out of scope here, however.Comment #27
yesct commentedok. updating the issue summary to reflect what I understand about this issue.
Comment #28
yesct commentedComment #29
alexpottCommitted c1b037d and pushed to 8.0.x. Thanks!
Comment #31
mile23Woot made it in!
Here's a follow-up to #26: #2377715: Expand unit testing for Drupal/Core/Entity/Sql/SqlContentEntityStorageSchema::performFieldSchemaOperation()