Bug: `#[CoversNothing]` is ignored in Cest tests with PHPUnit 13 / php-code-coverage 12

Offen
#6,940 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

Bewertung

Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Anfängerfreundlichkeit
68/100
Issue-Typ
Bug
Klarheit
Klar beschrieben
Aktivitätsstatus
Ruhig
Tech-Stack
php
Bereich
testing-qa

Rechercherichtung

Beginne mit src/Codeception/Test/Cest.php und src/Codeception/Test/Feature/CodeCoverage.php und führe dann mit dem bereitgestellten Cest-Beispiel vendor/bin/codecept run --coverage aus. Verfolge, wie CoversNothing und false coverage targets in PHPUnit 13 und php-code-coverage 12 behandelt werden. Fertig ist die Aufgabe, wenn CoversNothing-Tests weder abstürzen noch zur Coverage beitragen.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Beschreibung

##Bug: #[CoversNothing] is ignored in Cest tests with PHPUnit 13 / php-code-coverage 12

Environment
  • codeception/codeception: ^5.3.5
  • phpunit/phpunit: ^13.0
  • phpunit/php-code-coverage: ^12.0
Steps to reproduce
use PHPUnit\Framework\Attributes\CoversNothing;

#[CoversNothing]
class SomeCest
{
    public function someTest(\AcceptanceTester $I): void
    {
        // ...
    }
}

Run: vendor/bin/codecept run --coverage

Expected: test does not contribute to code coverage.
Actual: TypeError crash — or, if getLinesToBeCovered() returns [],
the test silently contributes to coverage as if the attribute were absent.


Root cause (two-part)

Part 1 — Cest::getLinesToBeCovered() does not handle CoversNothing

PHPUnit\Metadata\Api\CodeCoverage::coversTargets() in PHPUnit 13 handles only
CoversClass, CoversMethod, CoversTrait, etc.
It does not handle #[CoversNothing] — it simply returns an empty TargetCollection.

The correct PHPUnit 13 API for CoversNothing is shouldCodeCoverageBeCollectedFor():

// PHPUnit 13 — PHPUnit\Metadata\Api\CodeCoverage
public function shouldCodeCoverageBeCollectedFor(TestCase $test): bool
{
    if ($parser->forClass($test::class)->isCoversNothing()->isNotEmpty()) {
        return false;
    }
    return true;
}

But Cest::getLinesToBeCovered() never calls it, so CoversNothing is lost.

Part 2 — CodeCoverage trait does not handle false return value for php-code-coverage ≥ 12

Historically getLinesToBeCovered() returned false for @coversNothing.
In Feature/CodeCoverage.php, when php-code-coverage >= 12, the result is passed
directly to TargetCollection::fromArray(), which does not accept false:

Proposed fix

1. src/Codeception/Test/Cest.php — check CoversNothing before delegating to coversTargets():

public function getLinesToBeCovered(): array|bool
{
    if (PHPUnitVersion::series() < 10) {
        return TestUtil::getLinesToBeCovered($this->testClass, $this->testMethod);
    }

    $metadata = \PHPUnit\Metadata\Parser\Registry::parser()
        ->forClassAndMethod($this->testClass, $this->testMethod);

    if ($metadata->isCoversNothing()->isNotEmpty()) {
        return false;
    }

    if (version_compare(CodeCoverageVersion::id(), '12', '>=')) {
        return (new CodeCoverage())->coversTargets($this->testClass, $this->testMethod)->asArray();
    }

    return (new CodeCoverage())->linesToBeCovered($this->testClass, $this->testMethod);
}

2. src/Codeception/Test/Feature/CodeCoverage.php — handle false before calling TargetCollection::fromArray():

if (version_compare(CodeCoverageVersion::id(), '12', '>=')) {
    $tcClass = 'SebastianBergmann\\CodeCoverage\\Test\\Target\\TargetCollection';
    if (class_exists($tcClass) && method_exists($tcClass, 'fromArray')) {
        if ($linesToBeCovered === false) {
            $codeCoverage->stop(false, $status);
            return;
        }
        $linesToBeCovered = $tcClass::fromArray($linesToBeCovered);
        $linesToBeUsed    = $tcClass::fromArray($linesToBeUsed);
    }
}
$codeCoverage->stop(true, $status, $linesToBeCovered, $linesToBeUsed);

Both changes are needed: the first makes CoversNothing detectable again,
the second prevents the TypeError crash when the false value reaches fromArray().

Vorherrschende Sprache
PHP
Sterne
4.9k
Forks
1.3k
PR-Merge-Kennzahlen
Keine gemergten PRs in 30 T.

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
  3. Forken Sie das Repository und arbeiten Sie in einem Branch.
  4. Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.

Mehr aus Codeception/Codeception

Alle Issues in Codeception/Codeception

Ähnliche Issues

Weitere Issues zu PHP

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.