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

[Feature request] Report willReturn values incompatible with method signature #48

Open
Slamdunk opened this issue Jun 13, 2019 · 4 comments

Comments

@Slamdunk
Copy link

Given

class MyClass
{
    public function foo(): string {}
}

class MyOtherClassTest extends \PHPUnit\Framework\TestCase
{
    public function testFooMock()
    {
        $class = $this->createMock(MyClass::class);
        $class
            ->expects(static::once())
            ->method('foo')
            ->willReturn(123)
        ;
    }
}

PHPUnit reports:

PHPUnit 8.2.0 by Sebastian Bergmann and contributors.

W                                                                  1 /  1 (100%)

Time: 173 ms, Memory: 16.00 MB

There was 1 warning:

1) MyOtherClassTest::testFooMock
Method foo may not return value of type int

WARNINGS!
Tests:  1, Assertions:    0, Warnings: 1.

It would be awesome if PHPStan could report this errors too.

@ondrejmirtes
Copy link
Member

This is a good idea. Can you take a look at it?

@Slamdunk
Copy link
Author

Slamdunk commented Jun 14, 2019

Here we would have 3 involved parts:

  1. the $class object
  2. the method method with its argument
  3. the willReturn method with its argument.

I have no idea where to start a Rule like this. Anything similar you can point us out?

@ondrejmirtes
Copy link
Member

After:

$class = $this->createMock(MyClass::class);

$class is MyClass&MockObject.

expects() returns InvocationMocker. You'd need to write InvocationMockerType (extends ObjectType) that contains the mocked class + dynamic return type extension that makes sure that $mockObject->expects() returns InvocationMockerType.

Then you'd need to write another dynamic return type extension that makes sure that methods called on InvocationMockerType return the same type so that InvocationMockerType preserved across multiple calls.

Also, InvocationMockerType should probably have a second constructor argument with a method name. Once you call ->method(), it should know about both the mocked class and the mocked method.

Finally, you'd be able to write a rule that checks that calling ->willReturn on InvocationMockerType(MyClass, foo) has the correct argument type.

You should check out phpstan-doctrine (https://github.com/phpstan/phpstan-doctrine/tree/master/src/Type/Doctrine/QueryBuilder), there's a lot of similar code that analyses DQLs.

@Slamdunk
Copy link
Author

Great help 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants