我不知道如何PHPUnit测试棘轮/套接字

问题描述

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

我正在重新编程一年前使用TDD编写的程序。该程序不是那么复杂。它侦听网络套接字(Ratchet),接收信息,解析信息并通过消息总线(RabbitMQ)发送消息。

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

我的侦听器类有4种方法

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

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

  • 如何模拟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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...