New and noteworthy: PHPStan and PHPUnit integration
In this article we will have a brief look into the latest update to phpstan/phpstan-phpunit 2.0.8.
PHPStan validates PHPUnit data-providers
One of the features, which I am most proud of is the data-provider validation. It was requested by several people years ago, but we did not yet have a good idea how to make it happen without major changes in the PHPStan core.
Starting with this release, we take each data-set of a data-provider and check it against the signature of the corresponding test-case.
At the time of writing we support multiple kinds of data-providers:
@test#[Test]- “test*” method name prefix
@dataProvider#[DataProvider]staticdata-provider- non-
staticdata-provider return []data-providersyield []data-providersyield from []data-providers- named arguments in data-providers
See it in action:
#[DataProvider('aProvider')]
public function testTrim(string $expectedResult, string $input): void
{
}
public function aProvider(): array
{
return [
[
'Hello World',
" Hello World \n",
],
[
// Parameter #2 $input of method FooTest::testTrim() expects string, int given.
'Hello World',
123,
],
[
// Parameter #2 $input of method FooTest::testTrim() expects string, false given.
'Hello World',
false,
],
[
// Method FooTest::testTrim() invoked with 1 parameter, 2 required.
'Hello World',
],
];
}
For this to happen we re-use existing rules for method call validation via the newly introduced NodeCallbackInvoker.
This new interface allows us to create virtual made-up AST nodes, and handle them like regular method calls.
Related pull requests:
Ignore missingType.iterableValue for data-providers
You likely have been haunted by this error in your test-suite:
Method DataProviderIterableValueTest\Foo::dataProvider() return type has no value type specified in iterable type iterable.
Even in the PHPStan-src codebase this error was ignored by NEON config in the past, as it was really not that useful to repeat all types in every data-provider, which were already present in the test-case method signatures.
As you already saw in the above paragraph we learned how to validate data-providers with this release.
We went one step further and re-used the existing validation logic to omit the missingType.iterableValue error only for those data-providers which we are able to validate.
This is possible by implementing a new IgnoreErrorExtension.
Improved assertArrayHasKey() inference
Based on a fix in the PHPStan core, we are now able to properly narrow types after a call to PHPUnits’ assertArrayHasKey().
This will help to prevent false positive errors you may have experienced in the past.
PHPUnit version detector
With the addition of PHPUnitVersionDetector
we will be able to easily implement rules or extensions tailored to certain PHPUnit versions.
This will be useful in the future, so we can for example assist in PHPUnit migrations and pave the way for a smoother upgrade path.
Performance improvements
People reading my blog or social media posts know my obsession in making things faster. This release is no difference, as some changes have been done to make most PHPUnit specific rules more efficient by reducing unnecessary work.
Easter eggs included
There is even more magic under the hood.
We have a experimental feature in PHPStan which allows us to not just report errors, but also --fix some of them.
This new ability was also added to a few assert* rules.
For example, we can turn $this->assertSame(true, $this->returnBool()); into $this->assertTrue($this->returnBool());.
Summary
I spent a lot of time over a few weeks to make the PHPUnit integration shine. We are on a totally new level and even more new cool stuff is getting possible.
Make sure your boss considers sponsoring my open source work, so I can spend more time on your beloved code quality tooling.
Found a bug? Please help improve this article.