WordPress.org

Make WordPress Core

Opened 4 years ago

Last modified 34 hours ago

#39265 accepted task (blessed)

Missing @covers in the comment blocks in PHPUnit tests

Reported by: pbearne Owned by: SergeyBiryukov
Milestone: 5.6 Priority: normal
Severity: normal Version: 4.8
Component: Build/Test Tools Keywords: php8
Focuses: Cc:

Description (last modified by SergeyBiryukov)

PHPUnit has a comment block notation @cover and @uses that we are not using so we can create coverage report to see how much of WordPress has tests

https://thephp.cc/news/2014/03/phpunit-4-0-code-coverage-improvements
http://blog.teamlazerbeez.com/2009/08/18/phpunit-annotations/#covers
https://phpunit.de/manual/current/en/appendixes.annotations.html#appendixes.annotations.covers

@covers tells PHPUnit that this test what the test function is testing

    /**
     * @covers Class_Name::function_name
     */

@uses tells PHPunit that the test is using another function to help test the @covers function but this test is not testing it so it should ignore it for the covers report

     /**
     * @covers Class_Name::function_name
     * @uses   Other function
     */

note: if the @ covers function that is not in a class and in global namespace then the notation is like this

     /**
     * @covers ::function_name
     */

This ticket is place holder for how and what the changes need to be so that we can encourage the fixing of this.

Attachments (18)

39265-clean-covers-tags.patch (65.0 KB) - added by jrf 2 months ago.
Clean up some existing @covers tags. The () at the end is unnecessary and disregarded by PHPUnit, so can be removed.
functions_folder.patch (36.0 KB) - added by pbearne 8 weeks ago.
Covers add to Functions folder
d_folders.patch (57.9 KB) - added by patopaiar 8 weeks ago.
Adds @covers to folders starting with d: date, db and dependencies
e_folders.patch (7.8 KB) - added by patopaiar 7 weeks ago.
Adds @covers to folders starting with e: editor, error-protection, export, external-http
g_folders.patch (29.0 KB) - added by patopaiar 7 weeks ago.
Adds @covers to folders starting with g: general
L_folders.patch (20.2 KB) - added by sephsekla 7 weeks ago.
Adds @covers to folders starting with L: link, load
h_folders.patch (29.1 KB) - added by patopaiar 7 weeks ago.
Adds @covers to folders starting with h: hooks, http
root.patch (264.7 KB) - added by pbearne 2 weeks ago.
all the files in the root of test
39265-more-fixes.patch (7.4 KB) - added by jrf 6 days ago.
Fix newly introduced incorrect @covers tags. When global functions are covered, they need to be prefixed with :: (double colon) to distinguish them from class name. See: https://phpunit.readthedocs.io/en/7.0/annotations.html#covers
functions_folder.2.patch (36.0 KB) - added by pbearne 5 days ago.
update functions folder
d_folders.2.patch (60.8 KB) - added by patopaiar 5 days ago.
e_folders.2.patch (7.9 KB) - added by patopaiar 5 days ago.
g_folders.2.patch (29.0 KB) - added by patopaiar 5 days ago.
h_folders.2.patch (29.3 KB) - added by patopaiar 5 days ago.
query.php_fixed_test.patch (1.6 KB) - added by patopaiar 5 days ago.
L_folders-v2.patch (20.1 KB) - added by sephsekla 5 days ago.
Adds @covers to folders starting with L: link, load (amended)
root.2.patch (260.0 KB) - added by pbearne 5 days ago.
updated root patch
actions+admin.diff (44.7 KB) - added by Hudson Atwell 34 hours ago.
Adding @covers to Actions folder and Admin folder, Ajax and Attachment folders still need coverage. Hoping I did this well.

Download all attachments as: .zip

Change History (45)

This ticket was mentioned in Slack in #core by pbearne. View the logs.


4 years ago

#2 @jnylen0
4 years ago

While I am definitely a proponent of thorough unit tests, I am -1 on adding annotations for code coverage, and in general I think the @covers annotation is not a good idea. I will try to explain why.

Someone will have to update every single test to indicate which functions are covered. This will be a manual process requiring an enormous amount of effort, not only now, but in perpetuity. I can't speak for everyone but I personally don't want to do this in my patches.

It is virtually guaranteed that tests will not be consistently updated with @covers annotations in the future. (It's hard enough to ensure that tests are written in the first place.) Even if we do a huge effort now to add them, the coverage reports will become essentially useless in the future due to attrition.

Per-function coverage is not a very useful thing to report on. Consider: @covers wp_update_post. This is a very long function with a lot of complicated logic. Line-by-line coverage reporting is far more useful.

I don't want to read lots of lines of @covers and other annotations in the test code. I think we already have too many of these annotations and they are just visual noise, because the information about which functions are called is already present in the test code itself.

I would be far more interested in an effort to provide automated code coverage reports on a line-by-line basis, perhaps with results split by WordPress component or something like that. I do think this would be really valuable, and once it's set up, there's far less ongoing maintenance required.

#3 @pbearne
4 years ago

Hi @jnylen0

How would we go about providing automated code coverage reports on a line-by-line basis? This would good but can it be done?

A good test will only be testing one function so I expect to see just one @covers per test.

We went through the code base and add comments to actions and filters this a smaller task and we already have volunteers to do the heavy lifting who just waiting for the OK to get started

Paul

#4 @jnylen0
4 years ago

Most of https://phpunit.de/manual/current/en/code-coverage-analysis.html is dedicated to setting up automated code coverage.

Reading closer, the @covers annotation is a supplement to this automated coverage, and I don't think you can generate a report from manual annotations only.

@jorbin has already set this up: https://daily.jorb.in/2015/10/automated-code-coverage-of-wordpress-core-php-code/

The basic way to run it is as follows, but I get a mysterious error when I do so:

$ phpunit --coverage-html coverage-dir
Installing...
Running as single site... To run multisite, use -c tests/phpunit/multisite.xml
Not running ajax tests. To execute these, use --group ajax.
Not running ms-files tests. To execute these, use --group ms-files.
Not running external-http tests. To execute these, use --group external-http.
PHPUnit 5.7.15 by Sebastian Bergmann and contributors.

Cannot modify header information - headers already sent by (output started at /home/james/wp/wordpress-develop-official/tests/phpunit/includes/bootstrap.php:62)

#5 @pbearne
4 years ago

So the end point is to get coverage reports so if this work then we are good

The error is due to print statements e.g. "Installing..." there is a bug ticket for that we need away to turn it off for coverage reports.

Last edited 4 years ago by pbearne (previous) (diff)

#6 @tloureiro
4 years ago

Hey, @jnylen0 what version of phpunit are you using?
I got the same bug in version 5.1.3. Downloading and using the phpunit 5.7 version .phar worked for me. The report was generated successfully and it looks like this:
https://ibb.co/e4UNAk

Also, I couldn't see any results for code coverage in @jorbin's page (https://codecov.io/gh/aaronjorbin/wordpress.codecov)

#7 @jrf
2 months ago

  • Milestone changed from Awaiting Review to 5.6

I'd highly recommend for this ticket to be revisited for WP 5.6.

As explained in more detail in #50902, there are significant changes in PHP 8.0 which we will only be able to detect breakage from via unit tests.

Knowing which code is not, or insufficiently, covered by tests will allow a more focused approach for expanding the test suite to ensure compatibility with PHP 8.0.


Regarding the use of the @covers tags, reading the above discussion there seems to be some confusion about what that tag does and why it is so extremely useful (and important!), so let me try and explain it:

Let's take a unit test which is set up to test function foo(). Function foo() calls the functions bar() and baz() under the hood as part of its logic.

Now when running a code-coverage report, you will see that code coverage is recorded for function foo(), bar() and baz(), while in reality we were only testing function foo().
This is called incidental code coverage - covering code in functions/classes/methods which are not explicitly being tested. It is basically a false positive for which code is covered by a test.

With incidental code coverage, it is easy to think your code base has a high test coverage, while in reality there are no dedicated tests for a lot of the code.

In comes the @covers tag. The @covers tag ensures that only the code from the functions/methods/classes listed in @covers tag will be regarded as being covered by a specific test.
So, when we add a @covers ::foo tag to the test from the example and run code coverage again, we will see that code coverage has only been recorded for the code from the foo() function and that the bar() and baz() functions have 0% code coverage.

Once @covers tags have been added to all tests, the next step would be to add the forceCoversAnnotation=true setting in the phpunit.xml.dist configuration file. With that setting turned on, code coverage will only be recorded if a test has a @covers annotation. This effectively prevents incidental code coverage from entering the code coverage reports as only the code covered by tests with a @covers tag will be included.

Also note: The tests don't all have to have individual @covers tags. If a test class, through a variety of tests, covers all aspect of one particular function, a single @covers tag for that function in the test class docblock will suffice. Same if a test class covers every aspect of a class. A single @covers tag referencing the covered class in the test class docblock is enough in that case.

For more information, have a look at: https://phpunit.readthedocs.io/en/7.5/annotations.html#covers, https://phpunit.readthedocs.io/en/7.5/code-coverage-analysis.html#specifying-covered-code-parts and https://phpunit.readthedocs.io/en/7.5/risky-tests.html#risky-tests-unintentionally-covered-code

Last edited 2 months ago by jrf (previous) (diff)

#8 @jrf
2 months ago

Oh and regarding the @uses tag - I would leave that out, using that tag in combination with the beStrictAboutCoversAnnotation=true setting will mark a test as "Risky" if code is executed during the test which is not annotated via @covers or @uses tags.

That would make the maintainance of the tags very fiddly, while adding little additional value for this test code base.

#9 @SergeyBiryukov
2 months ago

  • Description modified (diff)
  • Owner set to SergeyBiryukov
  • Status changed from new to accepted
  • Summary changed from Missing @covers and @uses in the comments block in phpunt test for wordpress to Missing @covers in the comment blocks in PHPUnit tests

#10 follow-up: @pbearne
2 months ago

Are we go on for lots of little patches or should this get done on github and get pushed one big patch?

Glad to see this getting picked up

Paul

#11 in reply to: ↑ 10 @jrf
2 months ago

Replying to pbearne:

Are we go on for lots of little patches or should this get done on github and get pushed one big patch?

@pbearne Well, it is a lot of work and to do this right, every tests without the @covers tag will need to "studied" to see what the test coverage intention was when the test was added, possibly tracing this back to the patch/ticket via which the test was added etc. For some this will be simple (only one WP method/function is being called), for some not so much.

With that in mind, I think starting with small patches, something like a file (if complex) or directory (if not that complex) at a time, would probably be the way forward.

Once the number of @covers tags has increased significantly, we could consider one final patch to finish it off.

I'm working on setting up a PHPUnit QA standard for PHP_CodeSniffer which could help detect missing @covers tags as well as incorrect ones. Unfortunately that isn't public yet, though the YoastCS PHP_CodeSniffer standard contains some preliminary versions of sniffs, but those are in part too specificly attuned to their codebases to be used for WP Core for now.

All the same, if I adjust those slightly and do a scan, I currently see there are (at least) 3298 test methods which don't have a @covers tag either at the method or the class level and 191 @covers tags for which the () at the end should be removed. That last bit can be auto-fixed, so I'll upload a patch for that in a minute.

@jrf
2 months ago

Clean up some existing @covers tags. The () at the end is unnecessary and disregarded by PHPUnit, so can be removed.

#12 @SergeyBiryukov
2 months ago

In 48858:

Tests: Clean up some existing @covers tags.

The () at the end is unnecessary and disregarded by PHPUnit, so can be removed.

Props jrf.
See #39265.

#13 follow-up: @pbearne
2 months ago

So let's have patch per folder and one for the root
this will 51 patches this will be a good way to split the task up
I am working with a group at codeable.io to do this a project :-)

if we get this done quickly should add the @uses or not?

#14 in reply to: ↑ 13 @SergeyBiryukov
2 months ago

Replying to pbearne:

if we get this done quickly should add the @uses or not?

Per comment:8, I think @uses should not be added.

Per the documentation standards:

Note: This tag has been used in the past, but should no longer be used.

@pbearne
8 weeks ago

Covers add to Functions folder

@patopaiar
8 weeks ago

Adds @covers to folders starting with d: date, db and dependencies

This ticket was mentioned in Slack in #core-site-health by jrf. View the logs.


8 weeks ago

#16 @TimothyBlynJacobs
8 weeks ago

@jrf Do you have suggestions on how @covers should be used with the REST API endpoint tests? We are generally doing more “end-to-end” like tests. In other words actually creating a request object and dispatching it to the server instead of calling the controller methods directly.

@patopaiar
7 weeks ago

Adds @covers to folders starting with e: editor, error-protection, export, external-http

@patopaiar
7 weeks ago

Adds @covers to folders starting with g: general

This ticket was mentioned in Slack in #core by sergey. View the logs.


7 weeks ago

#18 @SergeyBiryukov
7 weeks ago

  • Keywords php8 added

@sephsekla
7 weeks ago

Adds @covers to folders starting with L: link, load

@patopaiar
7 weeks ago

Adds @covers to folders starting with h: hooks, http

#19 @SergeyBiryukov
6 weeks ago

In 49006:

Tests: Add missing @covers tags for files in phpunit/tests/functions/.

Props pbearne, jrf.
See #39265.

This ticket was mentioned in Slack in #core by hellofromtonya. View the logs.


5 weeks ago

#21 @pbearne
5 weeks ago

Question: should we add a note if the test doesn't cover a WP function?

eg the feeds test looks at content in the feed, not a function :-)

And test_mysqli_flush_sync this test the SQL functions

PS

this the list of updates promised by the codeable team
Chase Gruszewski : rest-api
Paul Bearne : all the f,root
Hudson Hudson: All the As
Jonathan Bossenger: All the Bs
Tamara M: All the Ds - Es - Gs - Hs
Joe B-R: All the Ls

@pbearne
2 weeks ago

all the files in the root of test

#22 @pbearne
2 weeks ago

Got the root files done now just few folder left

#23 @SergeyBiryukov
11 days ago

  • Type changed from enhancement to task (blessed)

@jrf
6 days ago

Fix newly introduced incorrect @covers tags. When global functions are covered, they need to be prefixed with :: (double colon) to distinguish them from class name. See: https://phpunit.readthedocs.io/en/7.0/annotations.html#covers

#24 @jrf
6 days ago

I've done an initial review of the submitted patches adding new covers tags for commit readiness.
I have NOT verified whether the added tags are correct. I trust this has been thoroughly fetted by the person who created the patch. I've only left a remark on those here and there when what I saw triggered an instance response.

Thank you all for stepping up and creating these patches! <3 This is a huge amount of work you've all done and getting these patches committed will be a great step forward!

Please find my feedback below. Line numbers I refer to are generally the "new" line number. File names as per the patch.

functions_folder.patch

@pbearne

  • @covers syntax is correct.
  • In a number of places superfluous empty docblocks lines are introduced at the start or end of a docblock. These need to be removed. Examples:
    • tests/phpunit/tests/functions/allowedProtocols.php line 19.
    • tests/phpunit/tests/functions/canonicalCharset.php all except the last one.
    • tests/phpunit/tests/functions/wpAuthCheck.php line 31.
  • @covers tags need to be in docblock comments, i.e. the comment block needs to start with /**. In file tests/phpunit/tests/functions/wpListFilter.php, changes between line 42 and 162, this is not the case.

d_folders.patch

@patopaiar

  • @covers syntax is correct.
  • date/currentTime.php - indentation of the code on line 37 seems to have become borked.
  • date/dateI18n.php - line 43 to 115 - need docblock format (see point 3 above) and alignment of the stars.
  • date/dateI18n.php line 143, indentation of the comment starter is off.
  • date/maybeDeclineDate.php - line 65 introduces a superfluous empty line.
  • date/query.php :+1: on adding descriptions for the tests. The descriptions do still need a period . as "end of sentence" punctuation and most of these fixes all need docblock format + alignment of the stars.
  • date/query.php line 310 + 313 introduce fixes to the actual test. This does not belong with this ticket and should be done in a separate patch, though the actual changes look good. :+1:
  • date/query.php line 636, 647, 670, 768 - empty comment line at start of docblock needs to be removed.
  • dependencies/scripts.php, line 684, 939 - something wonky is going on with the star indentation/alignment.

e_folders.patch

@patopaiar

  • @covers syntax is correct.
  • editor/wpEditors.php - these all need docblock format and the last one also removal of the stray empty line + alignment of the stars.
  • error-protection/recovery-mode-cookie-service.php line 94, ReflectionMethod::invoke is a PHP native method and should not be included in the @covers tags.
  • external-http/basic.php - needs docblock format, alignment of the stars and removal of a stray blank line above the new docblock (two empty lines at start of class instead of one).

g_folders.patch

@patopaiar

  • This patch seems to miss the path to the files. This probably has to do with from which folder the patch was generated. Generally speaking it is always a good idea to generate patches from the project root so file references have the full relative path.
  • @covers syntax is correct.
  • document-title.php - these all need docblock format and alignment of the stars.
  • paginateLinks.php - the new comment blockse all need docblock format.
  • resourceHints.php, line 224, 239 - star alignment is off.
  • template.php, line 418 introduces a stray blank line.

L_folders.patch

@sephsekla

  • @covers syntax is correct.
  • tests/phpunit/tests/link/adminUrl.php, tests/phpunit/tests/link/getAdjacentPost.php, tests/phpunit/tests/link/getAdjacentPostLink.php, tests/phpunit/tests/link/getDashboardUrl.php, tests/phpunit/tests/link/getPostCommentsFeedLink.php, tests/phpunit/tests/link/getPostTypeArchiveLink.php - if all tests cover the same function, the @covers tag at the class level is sufficient. Otherwise, the @covers tag at class level should be removed. Generally speaking, having @covers tags at test function level is better as it allows for more flexibility, so I'd recommend removing the one(s) at the class level.
  • tests/phpunit/tests/link/getAdjacentPostLink.php, tests/phpunit/tests/link/getPostCommentsFeedLink.php, tests/phpunit/tests/link/getPreviewPostLink.php, tests/phpunit/tests/link/getPreviousCommentsLink.php - stray blank lines at the start of the docblocks need to be removed.

g_folders.patch

@patopaiar

  • @covers syntax is correct.
  • Same as with other patches, new comment blocks need to use docblock format and the stars need to be aligned (nearly all files).
  • http/functions.php line 214 - star alignment is off.
  • http/http.php line 218 - introduces a stray blank line.
  • http/http.php line 274 - ReflectionClass::getConstants is a PHP native method and should not be included in the @covers tags.

root.patch

@pbearne

  • This patch seems to contain unrelated changes to the package-lock.json file. Please remove these.
  • @covers syntax is correct in nearly all cases.
  • tests/phpunit/tests/actions.php, tests/phpunit/tests/auth.php, tests/phpunit/tests/avatar.php, tests/phpunit/tests/cache.php, tests/phpunit/tests/comment-submission.php, tests/phpunit/tests/comment.php etc - stray blank lines at the start of docblocks need to be removed.
  • tests/phpunit/tests/adminbar.php, line 254 - 260 - the get_standard_admin_bar() method is not a test method, but a test helper. This should not have a @covers tag. Also: stray blank lines at the start of the docblock.
  • tests/phpunit/tests/adminbar.php, line 373 - stray blank comment line between two @covers tags.
  • tests/phpunit/tests/adminbar.php, line 750 - superfluous blank comment line (two instead of one).
  • tests/phpunit/tests/auth.php, line 116 seems to change a test ?
  • tests/phpunit/tests/auth.php, line 145-146 need to be removed (duplicate).
  • tests/phpunit/tests/basic.php line 6 - there is a tag for that ;-) @coversNothing See: https://phpunit.readthedocs.io/en/7.0/annotations.html#coversnothing .
  • tests/phpunit/tests/db.php line 238, 255, 793 introduce stray blank comment lines which should be removed.
  • tests/phpunit/tests/db.php, line 1687 - missing :: before the covered function name.
  • tests/phpunit/tests/db.php, line 1826 - 1828 seem incorrect.
  • tests/phpunit/tests/filters.php, line 422 introduces a stray blank comment line.
  • tests/phpunit/tests/link.php, line 131 seems to change a test ?
  • tests/phpunit/tests/mail.php, line 454 - PHPMailer is not included in code coverage reporting, so this should probably be changed to @coversNothing.
  • tests/phpunit/tests/media.php, line 522 seems to change a test and break it...
  • tests/phpunit/tests/media.php, line 1541 seems to change a test and break it...
  • tests/phpunit/tests/media.php, line 2658 removes the ticket number. This should be brought back or if the ticket number did not belong with the test, the whole line should be removed.
  • tests/phpunit/tests/pluggable.php (both tests) - these look more like QA tests, than unit tests as they don't actually test the functioning of the functions. I think these tests would be better off being marked with @coversNothing.
  • tests/phpunit/tests/rest-api.php, line 1021-1023 introduces a stray blank docblock.
  • tests/phpunit/tests/user.php, line 201-202 - this method looks to test the magic __get(), __set(), __isset() and __unset() methods.
  • tests/phpunit/tests/user.php, line 250, 265 - tests cannot cover properties. I believe both these tests are actually testing the __unset() method.
  • tests/phpunit/tests/user.php, line 293, 307 - tests cannot cover properties.
  • tests/phpunit/tests/widgets.php, line 45 seems to change a test and break it...

#25 @SergeyBiryukov
6 days ago

In 49305:

Tests: Correct newly introduced @covers tags.

When global functions are covered, they need to be prefixed with :: (double colon) to distinguish them from class name.

See https://phpunit.readthedocs.io/en/7.0/annotations.html#covers for more details.

Follow-up to [49000], [49171].

Props jrf.
See #39265.

#26 @patopaiar
5 days ago

@jrf I have made all the updates suggested in your notes - including creating a separate patch for the correction made to the unit test, and generating the patch with the missing path from the project root as suggested so that it does have the full file paths.

It's my first time contributing to core and I'm wondering what's the protocol to submit these revised versions of the patches?
Simply attach the updated versions here?
Should they keep their names or get new ones?
And lastly, should the patch with the corrected unit test be attached here on in a different ticket?

Thanks in advance for the guidance

@pbearne
5 days ago

update functions folder

@sephsekla
5 days ago

Adds @covers to folders starting with L: link, load (amended)

@pbearne
5 days ago

updated root patch

@Hudson Atwell
34 hours ago

Adding @covers to Actions folder and Admin folder, Ajax and Attachment folders still need coverage. Hoping I did this well.

#27 @Hudson Atwell
34 hours ago

After uploading actions+admin.diff I noticed everyone was submitting .patch files.

Since uploading, I've tried following the instructions in this article (http://scribu.net/wordpress/svn-patches-from-git.html) to make the .diff file acceptable, by running this command: git diff --no-prefix > ~/actions+admin.diff.

If I run this command, will the .diff file be acceptable? Should I reupload the actions+admin.diff file after running this command?

Last edited 34 hours ago by Hudson Atwell (previous) (diff)
Note: See TracTickets for help on using tickets.