Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHPUnit 10 - Coverage with Attributes

Is it me or is it impossible to recreate the docblock metadata "@covers" with the "new" (they've been around for a while now) Attribute approach?

We used to write our tests like so:

/**
 * @coversDefaultClass \App\Foo
 */
final class FooTest
{
    /**
     * @test
     * @covers ::bar
     */
    public function can_it_bar(): void
    {
    }
}

But for the life of me I can't seem to reproduce the same results with #[CoversClass] and/or #[CoversFunction].

Anyone already figured this out?

We want to start migrating to Attributes because of the announcement made here that in PHPUnit 12 support for metadata in docblocks will be removed:

https://github.com/sebastianbergmann/phpunit/issues/4502

Thanks in advance

like image 632
lloydimus Avatar asked Sep 07 '25 08:09

lloydimus


2 Answers

A new PHPUnit\Framework\Attributes\CoversMethod attribute was recently added. So your new code would be annotated like this:

use App\Foo;
use PHPUnit\Framework\Attributes\CoversMethod;
use PHPUnit\Framework\Attributes\Test;

#[CoversMethod(Foo::class, "bar")]
final class FooTest
{
    #[Test]
    public function can_it_bar(): void
    {
    }
}

Unfortunately, as with the previous answer, it's still not able to be applied to test methods. So in the (likely) event you have multiple different test methods you will have to stack a bunch of CoversMethod attributes before the class.

like image 193
miken32 Avatar answered Sep 10 '25 00:09

miken32


As you said, it's impossible to reproduce the same behavior, but as far as I can understand you have to re-write you code like this:

<?php

use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\CoversFunction;
use PHPUnit\Framework\Attributes\Test;

#[CoversClass(\App\Foo::class)]
#[CoversFunction('bar')]
final class FooTest
{
  #[Test]
  public function can_it_bar(): void
  {
  }
}

You can even automate this using Rector and custom PhpUnit rules.

In my opinion the easiest thing to do is not use CoversFunction anymore and only use CoversClass.

like image 24
jawira Avatar answered Sep 10 '25 01:09

jawira