JereK
JereK

Reputation: 83

How do I mock an object in PHP that passes get_class inspection?

I have already encountered this thread, but my use case is slightly different since I don't create a new instance of the service I am gonna test, but get the instance and all its dependencies from a container. My question is how to get to a specific case in that switch-case logic?

Implementations:

interface MessageInterface { * my code * }

class MyFirstClass extends Message { * my code * }

class MySecondClass extends Message { * my code * }

class MyThirdClass extends Message { * my code * }

abstract class Message implements MessageInterface { * my code * }

public function sendMessage(MessageInterface $message) : void
{
    var_dump(get_class($message));
    // output: "Mock_MyFirstClass_c5f215a6"
    var_dump( MyFirstClass::class);
    // output: "My\Namespace\MyFirstClass"

    switch (get_class($message)) {
        case MyFirstClass::class:
            **how to get here?**
            $message->render();
            break;
        case MySecondClass::class:
            break;
        case MyThirdClass::class:
            break;
    }
}

Test:

    public function setUp() : void
    {
       parent::setUp();
       $this->myService = $this->container->getMyService();
    }

    public function testSendMessage() : void
    {
       $message = $this->createMock(MyFirstClass::class);

       $message->expects($this->once())->method("render");

       $this->myService->sendMessage($message);
    }

Upvotes: 0

Views: 1115

Answers (1)

iainn
iainn

Reputation: 17417

The short version is that if you're using createMock, you won't be able to use get_class. The mocks returned extend the class provided rather than implementing it directly, and doing a direct string-comparison on the class names isn't going to work.

Depending on the complexity of your message class, or if you can't modify your service, you might want to consider using a fixture instead. That is, just call $message = new MyFirstClass() rather than mocking it. Do you consider the message to be a dependency of the service, or it is simply an object to be processed? A fixture could make more sense for the second case. There is some much more detailed discussion about this on Martin Fowler's site, here: https://martinfowler.com/articles/mocksArentStubs.html

Alternatively, if you can modify the service, then you'll be able to use instanceof instead, since that will work with subclasses.

Rather than

switch (get_class($message)) {
  case MyFirstClass::class:
    ...

it'd be

if ($message instanceof MyFirstClass::class) {
   ...

Upvotes: 1

Related Questions