phpstan-mockery icon indicating copy to clipboard operation
phpstan-mockery copied to clipboard

Missing mock type information for Mockery\Expectation::getMock()

Open larsnystrom opened this issue 3 years ago • 1 comments
trafficstars

Mockery::mock() returns a Mockery\MockInterface. MockInterface::shouldReceive() et al returns an Mockery\Expectation, which in turn has a getMock() method to return the MockInterface the Expectation belongs to.

The problem is that phpstan says the return type of Expectation::getMock() is Mockery\MockInterface with no type information on what was originally mocked. So for example

interface A {
    foo(): void
}

function getMock(): A
{
    return Mockery::mock(A::class)
        ->shouldReceive('foo')
        ->getMock();
}

will cause the following phpstan error: Function getMock() should return A but returns Mockery\MockInterface.

Of course the code in getMock() can be rewritten to not be fluent so that the return value of Mockery::mock() is returned instead, however in many cases I mock objects inline in some other expression and when I do that it's really helpful to be able to use the fluent way of writing the expectations.

Is it possible to change the type of the return value of Mockery\Expectation::getMock() to include the type information of the original mock? With generics I guess it should be something like Mockery::mock(T): MockInterface<T>, MockInterface<T>::shouldReceive(): Expectation<T> and Expectation<T>::getMock(): MockInterface<T>.

larsnystrom avatar Jun 10 '22 10:06 larsnystrom

The problem is that non of these classes/interfaces are currently generic. The mocks are intersection types. We could probably make Expectation generic with T, and we could write a dynamic return type extension for shouldReceive so that when called on MockInterface&Foo, it returns Expectation<Foo>.

ondrejmirtes avatar Jun 10 '22 12:06 ondrejmirtes