The50
The50

Reputation: 1168

PHP Unit mocked objects types

What is the correct way of setting a type for mocked objects?

Example code:

/**
 * @dataProvider getTestDataProvider
 * @throws Exception
 */
public function testExampleData(
    Request $request,
    Response $expected,
    SomeClass $someClassMock
): void {
    $result = $someClassMock->getData($request);

    $this->assertEquals($expected, $result);
}

In this example the type of $someClassMock is class SomeClass. Also there is a type called MockObject which is also working properly, but it messes up the autocompletion of functions inside that class.

Which types should I use on these mocked objects? Real object class or MockObject?

Upvotes: 3

Views: 758

Answers (1)

Dirk Scholten
Dirk Scholten

Reputation: 1048

What I do to make sure the auto completion works for the mocked class as well as the MockObject, is tell php that it can be either class. This adds the auto complete for both and also makes it quite understandable for anyone reading the code that it is a mock and what object it is mocking.

In your case it would look like this:

/**
 * @dataProvider getTestDataProvider
 * @throws Exception
 */
public function testExampleData(
    Request $request,
    Response $expected,
    SomeClass|MockObject $someClassMock // <-- Change made here
): void {
    $result = $someClassMock->getData($request);

    $this->assertEquals($expected, $result);
}

You will still be passing in the MockObject, but your IDE will not complain about any unknown functions.

EDIT: To make it work with PHP versions before 8, I would suggest something like this (minimal example):

class ExampleTest extends TestCase 
{
    private someClass | MockObject $someClassMock;

    public function setUp(): void
    {
        $this->someClassMock = $this->createMock(SomeClass::Class);
    }

    public function testMe()
    {
        $this->someClassMock->expects($this->once())->method('getData')->willReturn('someStuff');
    }
}


In this scenario the variable $someClassMock is declared as both types and you can use it throughout your test with autocompletion for both of them. This should also work with your data provider although you might have to rewrite it slightly. I didn't include it in my example to keep it simple.

Upvotes: 4

Related Questions