Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test annotated with "@coversNothing" may lead to files missing from code coverage report #4947

Closed
sebastianbergmann opened this issue Mar 22, 2022 · 6 comments
Assignees
Labels
feature/code-coverage Issues related to code coverage (but not php-code-coverage) type/bug Something is broken

Comments

@sebastianbergmann
Copy link
Owner

phpunit.xml

<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.5/phpunit.xsd"
         bootstrap="vendor/autoload.php"
         cacheResultFile=".phpunit.cache/test-results"
         executionOrder="depends,defects"
         forceCoversAnnotation="true"
         beStrictAboutCoversAnnotation="true"
         beStrictAboutOutputDuringTests="true"
         beStrictAboutTodoAnnotatedTests="true"
         convertDeprecationsToExceptions="true"
         failOnRisky="true"
         failOnWarning="true"
         colors="true"
         verbose="true">
    <testsuites>
        <testsuite name="default">
            <directory>tests</directory>
        </testsuite>
    </testsuites>

    <coverage cacheDirectory=".phpunit.cache/code-coverage"
              processUncoveredFiles="true">
        <include>
            <directory suffix=".php">src</directory>
        </include>
    </coverage>
</phpunit>

src/Greeter.php

<?php declare(strict_types=1);
final class Greeter
{
    public function greet(string $name): string
    {
        return 'Hello, ' . $name;
    }
}

tests/GreeterTest.php

<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;

/**
 * @coversNothing
 */
final class GreeterTest extends TestCase
{
    public function testGreetsWithName(): void
    {
        $this->assertSame('Hello, Test', (new Greeter)->greet('Test'));
    }
}
$ ./vendor/bin/phpunit --coverage-html /tmp/coverage
PHPUnit 9.5.19 #StandWithUkraine

Runtime:       PHP 8.1.4 with PCOV 1.0.11
Configuration: /home/sb/bug/phpunit.xml

.                                                                   1 / 1 (100%)

Time: 00:00.005, Memory: 6.00 MB

OK (1 test, 1 assertion)

Generating code coverage report in HTML format ... done [00:00.006]

Actual

actual

Expected

expected

@sebastianbergmann
Copy link
Owner Author

@dvdoug @Slamdunk Do you guys have an idea why a sourcecode file does not show up in the report at all? Thanks!

@Slamdunk
Copy link
Contributor

Do you guys have an idea why a sourcecode file does not show up in the report at all?

No, but I can assure and confirm that return 'Hello, ' . $name; line is reported as executable by ExecutableLinesFindingVisitor so the culprit is somewhere else.

@sebastianbergmann
Copy link
Owner Author

That much I was able to figure out already. So sorry for not mentioning that.

@dvdoug
Copy link
Contributor

dvdoug commented Mar 23, 2022

Haven't stepped through with a debugger to confirm, but my theory would be this:

  • PHPUnit detects the @coversNothing annotation
  • PHPUnit runs the test, but opts not to call start()/stop() inside php-code-coverage because it doesn't see the need (see logic starting at
    $isAnyCoverageRequired = TestUtil::requiresCodeCoverageDataCollection($test);
    )
  • Therefore php-code-coverage does not obtain any data about the file during the actual execution of the test
  • PHPUnit asks php-code-coverage for the report
  • php-code-coverage runs processUncoveredFilesFromFilter() which correctly identifies that it does not have coverage data for Greeter.php
  • It starts the coverage driver, does an include_once on the file. Then stops coverage. At this point, normally data about the file would be picked up and processed.
  • However, unknown to php-code-coverage that file was already included/required earlier on during the test run. Therefore the include_once is actually a no-op, resulting in the coverage driver not reading/parsing/outputting any data about the file.

If any other test in a test suite (without @coversNothing) invoked that source code file in any way during execution I think it would show up in the report just fine, as the driver would then include data for it at that point

@sebastianbergmann
Copy link
Owner Author

sebastianbergmann commented Mar 24, 2022

That makes sense. Thank you, Doug!

This would mean, though, that the problem should not exist in master because there we no longer load uncovered files but instead use PHP-Parser to analyse them.

@sebastianbergmann
Copy link
Owner Author

This would mean, though, that the problem should not exist in master because there we no longer load uncovered files but instead use PHP-Parser to analyse them.

That is correct:

composer.json

{
    "autoload": {
        "classmap": [
            "src/"
        ]
    },
    "prefer-stable": true,
    "minimum-stability": "dev",
    "require-dev": {
        "phpunit/phpunit": "^10.0"
    }
}

phpunit.xml

<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.0/phpunit.xsd"
         bootstrap="vendor/autoload.php"
         cacheDirectory=".phpunit.cache"
         executionOrder="depends,defects"
         requireCoverageMetadata="true"
         beStrictAboutCoverageMetadata="true"
         beStrictAboutOutputDuringTests="true"
         convertDeprecationsToExceptions="true"
         failOnRisky="true"
         failOnWarning="true"
         colors="true"
         verbose="true">
    <testsuites>
        <testsuite name="default">
            <directory>tests</directory>
        </testsuite>
    </testsuites>

    <coverage>
        <include>
            <directory suffix=".php">src</directory>
        </include>
    </coverage>
</phpunit>

Actual

grafik

@sebastianbergmann sebastianbergmann transferred this issue from sebastianbergmann/php-code-coverage Mar 31, 2022
@sebastianbergmann sebastianbergmann changed the title PHPUnit test annotated with "@coversNothing" leads to file missing from code coverage report Test annotated with "@coversNothing" leads to file missing from code coverage report Mar 31, 2022
@sebastianbergmann sebastianbergmann self-assigned this Mar 31, 2022
@sebastianbergmann sebastianbergmann added the feature/code-coverage Issues related to code coverage (but not php-code-coverage) label Mar 31, 2022
@sebastianbergmann sebastianbergmann changed the title Test annotated with "@coversNothing" leads to file missing from code coverage report Test annotated with "@coversNothing" may lead to files missing from code coverage report Apr 1, 2022
@sebastianbergmann sebastianbergmann added type/bug Something is broken and removed bug labels Jun 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature/code-coverage Issues related to code coverage (but not php-code-coverage) type/bug Something is broken
Projects
None yet
Development

No branches or pull requests

3 participants