3

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?

1 Answer 1

4

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.

Sign up to request clarification or add additional context in comments.

5 Comments

Good idea, although union types is from PHP 8.0 only I think. I am running 7.3 at the moment.
I see you are using a dataprovider to provide the mock. Are you actually providing different mocks for every run? You could declare your $someClassMock as class variable and initialize it in the setUp() function. Then you can use the multi-type variable type declaration also before php8. I will edit my answer with an example
No, mocks is always the same on all the test runs. Main purpose of this question would be to find out the best way to use types on these mocks. Code is working either way, I wonder if there is any standard and good practice for it.
I've added an extra example, let me know if it makes any sense.
Yeah thats fine I think. Thank you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.