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

Support for methods added with addMethods phpunit function #87

Closed
lugus opened this issue Dec 10, 2020 · 12 comments
Closed

Support for methods added with addMethods phpunit function #87

lugus opened this issue Dec 10, 2020 · 12 comments

Comments

@lugus
Copy link

lugus commented Dec 10, 2020

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.
 ------ -----------------------------------------------------------------------------------------------
@VincentLanglet
Copy link
Contributor

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 ?

@VincentLanglet
Copy link
Contributor

I created a reproducer: #93

@ondrejmirtes
Copy link
Member

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?

@VincentLanglet
Copy link
Contributor

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.

@lugosium
Copy link

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

@ondrejmirtes
Copy link
Member

@method annotation is understood by PHPStan.

@VincentLanglet
Copy link
Contributor

VincentLanglet commented Mar 23, 2021

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 #93

@lugosium
Copy link

@method annotation is understood by PHPStan.

I was giving some use cases to reply your comment #87 (comment), it's indeed ok for @method, but do you have any solutions for the pgsqlGetNotify function?

@mpoiriert
Copy link

mpoiriert commented Jun 20, 2022

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.

@VincentLanglet
Copy link
Contributor

This issue might be closed since addMethods is deprecated cf sebastianbergmann/phpunit#5320 @ondrejmirtes

@ondrejmirtes
Copy link
Member

Thanks!

Copy link

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.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Dec 23, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants