【问题标题】:I can't figure out how to PHPUnit test Ratchet/Sockets我不知道如何 PHPUnit 测试 Ratchet/Sockets
【发布时间】:2021-02-11 09:25:40
【问题描述】:

首先让我承认,我绝对是 TDD 和单元测试领域的新手。目前,我正在学习与 TDD 合作以提升自己的职业生涯。

我正在重新编程我一年前使用 TDD 编写的程序。该程序并不复杂。它监听一个websocket(Ratchet),接收信息,解析信息,通过消息总线(RabbitMQ)发送消息。

我正在尝试通过 TDD 来解决这个问题,所以我首先开始编写我的测试。

我的监听器类有 4 个方法。

  • 连接(通过 Ratchet 连接到流)
  • 聆听(开始聆听)
  • 解析(解析收到的信息)
  • SendMessage(向 RabbitMQ 总线发送消息)

我在第一次写测试时遇到的问题。

  • 如何模拟 Ratchet 连接并断言我的函数可以“连接”
  • 我如何断言收到的信息符合我的期望

我发现很难找到关于这个特定主题的信息,我知道我的问题很广泛。我不期待一个完整的解决方案或答案,但希望有进一步研究该主题的术语以及有关为此类方法编写测试的讲座/教程。

【问题讨论】:

    标签: php testing phpunit tdd ratchet


    【解决方案1】:

    没有看过任何代码就很难争论。根据您的描述,听起来您有一门课可以做所有事情。这可能已经成为使测试变得比实际更难的原因。

    谈到单元测试,我喜欢坚持 Michael Feathers 的定义:

    如果满足以下条件,则测试不是单元测试:

    • 它与数据库对话。
    • 它通过网络进行通信。
    • 它涉及文件系统。
    • 它不能与您的任何其他单元测试同时运行。
    • 您必须对您的环境做一些特殊的事情(例如编辑配置文件)才能运行它。

    模拟 Ratchet 和 RabbitMQ 连接似乎是使测试符合上述定义的一种方式,但还有另外一句话:“不要模拟你不拥有的东西”。虽然这不是一个硬性规定,但我认为这是一个很好的指导方针。有很多关于这个主题的文章。 This should give you a good overview

    不过,Ratchet 在服务器和事件循环部分有点特别。但它经过了很好的测试,所以你不必这样做。我的建议:保持与 Ratchet 的集成如此简单,反正没有太多要测试的东西,直接跳过测试。

    final class MyRatchetApp implements MessageComponentInterface
    {
        private MessageProcessor $processor;
    
        public function __construct(MessageProcessor $processor)
        {
            $this->processor = $processor;
        }
    
        public function onMessage(ConnectionInterface $from, $msg)
        {
            $this->processor->handle($msg);
        }
        
        // ...
    }
    

    这会给你留下一个MessageProcessor,你可以单独测试它。它的所有依赖项都是您拥有的类型,因此您可以使用模拟、存根或假实现来测试它们的交互。此实现过于简化,并且遗漏了您肯定想做并且当然想测试的错误处理等内容。

    final class MessageProcessor
    {
        private MessageParser $parser;
    
        private MessageBroadcaster $broadcaster;
    
        public function __construct(MessageParser $parser, MessageBroadcaster $broadcaster)
        {
            $this->parser      = $parser;
            $this->broadcaster = $broadcaster;
        }
    
        public function handle(string $rawMessage): void
        {
            $this->broadcaster->send($this->parser->parse($rawMessage));
        }
    }
    
    interface MessageParser
    {
        /**
         * @throws BadMessageException
         */
        public function parse(string $message): Message;
    }
    
    interface MessageBroadcaster
    {
        /**
         * @throws UnsupportedMessageException
         * @throws UnroutableMessageException
         */
        public function send(Message $message): void;
    }
    

    创建MessageParser 的实现应该简单明了且易于进行单元测试。 MessageBroadcaster 的 RabbitMQ 实现将是集成测试的完美候选者。

    最后,为真正的应用程序将所有具体实现组合在一起。

    $server = IoServer::factory(
        new MyRatchetApp(
            new MessageProcessor(
                new CommandMessageParser(),
                new RabbitMqMessageBroadcaster()
            )
        ),
        8080
    );
    

    为确保所有部分协同工作,您可以创建一些端到端测试来执行完整的往返并验证结果。首先创建这些测试,允许您执行Double Loop TDD

    【讨论】:

      猜你喜欢
      • 2013-02-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-25
      • 1970-01-01
      • 2016-04-16
      • 2021-01-18
      • 2021-02-12
      相关资源
      最近更新 更多