如何模拟 PHP 中通过 get_class 检查的对象?

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

我已经遇到了 this 线程,但我的用例略有不同,因为我没有创建要测试的服务的新实例,而是从容器。我的问题是如何找到该切换案例逻辑中的特定案例?

实施:

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;
    }
}

测试:

    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);
    }

简而言之,如果您正在使用 createMock,您将无法使用 get_class。模拟返回 extend class 提供的而不是直接实现它,并且对 class 名称进行直接字符串比较是行不通的。

根据您的消息的复杂程度 class,或者如果您无法修改您的服务,您可能需要考虑改用固定装置。也就是说,只调用 $message = new MyFirstClass() 而不是模拟它。您认为消息是服务的依赖项,还是只是一个待处理的对象?对于第二种情况,夹具可能更有意义。在 Martin Fowler 的网站上有一些关于此的更详细的讨论,此处:https://martinfowler.com/articles/mocksArentStubs.html

或者,如果您可以修改服务,那么您就可以使用 instanceof,因为它可以与 subclasses 一起使用。

而不是

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

会是

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