phpstan-phpunit
phpstan-phpunit copied to clipboard
Support for methods added with addMethods phpunit function
Hello, thank you for your work.
Reporting issue about the onlyMethods from phpunit, it looks than phpstan-phpunit do not check methods added with these method and raise an error.
When:
$fooMock = $this->getMockBuilder(\stdClass::class)
->addMethods(['hello'])
->getMock();
$fooMock->method('hello')
->willReturn('Hello PHPStan');
------ -----------------------------------------------------------------------------------------------
Line Tests/Unit/FooTest.php
------ -----------------------------------------------------------------------------------------------
120 Trying to mock an undefined method hello() on class stdClass.
------ -----------------------------------------------------------------------------------------------
I just encountered this issue with the code
$object2 = $this->getMockBuilder(\stdClass::class)->addMethods(['addFooBar'])->getMock();
$object2->expects($this->once())->method('addFooBar')->with($instance);
Any recommendation @ondrejmirtes ?
I created a reproducer: https://github.com/phpstan/phpstan-phpunit/pull/93
I don't understand the use-case. If you're adding methods to the mock that don't exist on the mocked class, you'll also get PHPStan errors where you're calling the passed object in production code. e.g. Method addFooBar does not exist on stdClass.. Isn't it better to define an interface that requires those methods to be implemented?
The usecase is
$fieldDescription = $this->createMock(FieldDescriptionInterface::class);
$fieldDescription->expects($this->once())->method('getAssociationMapping')->willReturn(['fieldName' => 'fooBar']);
$fieldDescription->expects($this->once())->method('getParentAssociationMappings')->willReturn([]);
$instance = new \stdClass();
$object = $this->getMockBuilder(\stdClass::class)->setMethods(['addFooBar'])->getMock();
$object->expects($this->once())->method('addFooBar')->with($instance);
ObjectManipulator::addInstance($object, $instance, $fieldDescription);
Here, the method name addFooBar is dynamically generated because of the fieldName 'fooBar'.
There is no and never will interface for this.
Some situations where i use addMethods:
Some specific PDO driver functions e.g: https://www.php.net/manual/fr/pdo.pgsqlgetnotify.php
AWS class using @method phpdoc annotation e.g: https://github.com/aws/aws-sdk-php/blob/master/src/Athena/AthenaClient.php
@method annotation is understood by PHPStan.
The issue of @lugus and all the error I get is because we're adding methods to \stdClass.
The purpose of mocking a stdClass and adding method is to avoid to create a class just for the tests.
Since no method exist for \stdClass, what do you think about ignoring the method check for a mock of \stdClass ? @ondrejmirtes
I made the change in https://github.com/phpstan/phpstan-phpunit/pull/93
@methodannotation is understood by PHPStan.
I was giving some use cases to reply your comment https://github.com/phpstan/phpstan-phpunit/issues/87#issuecomment-804066678, it's indeed ok for @method, but do you have any solutions for the pgsqlGetNotify function?
I have other use case where a method expect an object with a specific interface (X), If the object implements another interface (Y) as well a specific method will be call. I want to test that if the object has the method of interface Y but don't implement the interface Y it will not be called.
This issue might be closed since addMethods is deprecated cf https://github.com/sebastianbergmann/phpunit/issues/5320 @ondrejmirtes
Thanks!
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.