0

我使用 http 服务器的新实现。我将创建单元测试,这将帮助我检查我的 TCP 连接状态的状态机是否正常工作。

当然我需要检查一些简单的事情,比如:我的服务器是closed在接收后切换到状态RST还是established在序列后切换到状态SYN, SYN+ACK, ACK

因为这个状态机中可能的路径数量很大,我想知道我应该关注哪些测试。

例如,Apache 是否有任何我可以从中获取模式的公共单元测试?

第二件事是......我应该从应用程序的角度开始创建这个测试,所以我应该专注于创建我可以使用简单的 java 套接字模拟的测试,使用像connect,send等命令。

4

4 回答 4

4

测试什么

每个单元测试策略的总体目标是:

  1. 完整的代码覆盖率:这意味着您的应用程序的每一行代码在完整的测试套件中至少执行一次。
  2. 规范的全面覆盖:通常,软件开发从功能规范开始,该规范准确地说明了软件的功能以及在每种可能的情况下它如何反应。规范中提到的每个要求都需要至少一个测试。当您没有规范时,最少测试的指南可能是HTTP 协议本身的规范

每当您测试服务器应用程序时,您必须记住,您不能假设您的客户端将是 HTTP 协议的完美实现。在现实世界中,您的服务器将面临错误地实现它或具有不可靠连接的客户端,这些客户端在您的应用程序的任何状态下都会突然终止。这甚至还没有考虑到故意尝试在您的服务器中查找和利用漏洞的恶意客户端。这些也是您需要测试用例的情况。

服务器通常是多线程的。这意味着应该测试多线程带来的常见问题(如竞争条件、死锁、同步问题、繁忙的自旋等)。不幸的是,这些问题很难预测,甚至更难编写有意义的单元测试。不仅因为这些问题通常通过不同组件的交互表现出来,这是集成和系统测试的范围,而不是单元测试。

如何测试

单元测试通常不应该依赖于外部资源,因为当它们这样做时,您是在测试该资源,而不是您自己的应用程序。当您的应用程序的功能严重依赖外部系统时,例如 http 服务器的情况,应该模拟其他系统。

这是通过使用模拟对象实现外部资源来完成的。模拟对象是代替依赖于外部资源的对象(通过扩展它或通过实现相同的接口)的对象,但仅模拟其行为。在网络服务器的上下文中,您将创建一个扩展Socket的类,但使用模拟外部客户端而不实际访问网络的东西覆盖 Socket 的所有方法。

然后,您可以在单元测试期间使用它来测试您的类,而不是普通的套接字。

这使您可以轻松实现特殊的模拟套接字来测试特殊的测试条件,例如响应缓慢、非常快或只是错误的客户端。

new Socket()您可能想知道“但是当我在我想要测试的类中创建一个内部时我应该怎么做呢”?答案是,为了使应用程序可单元测试,您不应该这样做。关键字是依赖注入。简而言之,依赖注入意味着一个类不应该使用new关键字,除非它是该类的工厂或生成器。一个类使用的任何对象都不应该由它创建。它们应该通过构造函数或 setter 方法提供给它。

例子:

因此,当您有一个ConnectionListener使用 aServerSocket等待客户端连接然后对它们执行某些操作的类时,您不应该在其构造函数中创建该 ServerSocket。相反,您应该将 ServerSocket 传递给 ConnectionListener 的构造函数。在生产代码中,这将是一个普通的服务器套接字。但是在您的单元测试中,您可以传递一个扩展 ServerSocket 的模拟对象。这个模拟对象将模拟一个或多个客户端,然后向单元测试框架报告 ConnectionListener 的行为是否符合预期。

于 2013-04-15T00:58:33.113 回答
3

当然,我需要检查一些简单的事情,例如:我的服务器是在收到 RST 后切换到关闭状态,还是在序列 SYN、SYN+ACK、ACK 之后切换到已建立状态。

当然不是。你没有资格测试这些。如果供应商的 TCP/IP 堆栈被破坏,它将很快在全世界变得明显。测试它是供应商的责任。您应该测试的是您自己的代码,在您自己的新 HTTP 服务器中。

于 2013-04-15T01:37:05.750 回答
2

我将首先创建一个状态机图,然后根据单个状态转换的数量(这是一个有限的数量,并且可能非常小)创建测试。

于 2013-04-19T18:11:16.593 回答
2

例如,Apache 是否有任何我可以从中获取模式的公共单元测试?

您可以查看Apache Tomcat 测试

于 2013-04-18T21:00:33.700 回答