到目前为止,你已经替换了Web服务器的资源了。接下来,我们要替换HTTP 连接。这样做的话会妨碍你有效地测试连接,但是这没关系,因为它并不是你此时真正的目的。你真正想要做的是测试解决方案中的代码。在后面的阶段中,可以使用功能测试或集成测试来测试连接。
当不需要改变代码就可以替换连接的时候,我们就会发现,得益于Java的URL和HttpURLConnection类,我们可以引人自定义的协议处理器来处理任何类型的通信协议。你可以使任何对HttpURLConnection类的调用指向你自己的测试类,这些类会返回测试中需要的任何内容。
为了实现一个自定义的URL 协议处理器,你需要调用URL的setURLStreamHandlerFactory方法,并传给它一个自定义的URLStreamHandlerFactory。无论何时调用URL的openConnection方法,都会调用URLStreamHandlerFactory 类返回一个URLStreamHandler对象。代码6.6给出了实现这个过程的代码。其想法是在JUnit的setUp方法中调用URL的静态方法 setURLStreamHandlerFactory。(更好的实现会使用到TestSetup类,以至于它在整个测试集执行期间只运行一次。)
为了能够使用StubHttpURLConnection类,我们使用了几个(内部)类(②和③)。我们从调用setURLStreamHandlerFactory1和第一个 stub类 StubstreamHandlerFactory开始。在StubstreamHandlerFactory 中,我们覆写createURLStreamHandler方法②,在这个方法中我们返回了第2个私有的stub类StubHttpURLStreamHandler的一个新实例。在StubHttpURLStream Handler中,我们覆写了一个方法 openConnection来根据给定的URL打开一个连接③。
为了简单起见,你也能够使用匿名的内部类,但是这个方法将会使得代码更加难以阅读。注意,你目前还没有编写StubHttpURLConnection类,我们会在下一节中详细介绍这个类。
最后一步将是创建一个HttpURLConnection类的stub实现,以便你可以返回测试中想要的任何值。代码6.7给出一个简单的实现,它返回字符串“It works”作为一个流传给调用者。
HttpURLConnection是一个抽象的公有类,它并没有实现一个接口,所以你可以继承它并覆写需要替换的方法。在这个stub 中,你提供了getInputstream方法的实现,因为它是待测代码所使用的唯一方法。如果待测代码较多地使用了HttpURLConnection 的API,那么你就需要替换这些额外的方法。这就是代码变得越来越复杂的原因所在——你需要完全复制与真正的HttpURLConnection相同的行为。例如,在①处,你测试了待测代码中的setDoInput(false)是否已经被调用了,然后调用getInputstream方法返回一个 ProtocolException异常(这就是HttpURLconnection的行为)。幸运的是,在多数情况下,你只需要替换些方法,而不是整个APl。
我们来运行TestWebclient1测试,它使用了StubHttpURLConnection。图6.5显示在Eclipse中执行该测试的结果。
正如你所看到的,替换连接要比替换 Web资源更加容易。这个方法与上文提到的方法相比,并没有执行相同程度的测试(你没有进行继承测试),但是它能使你更加容易地为Webclient逻辑编写专门的单元测试。
图6.5 执行TestWebClient1的结果(其使用了 StubHttpURLConnection )
在本章中,我们介绍了如何使用stub帮助我们对访问远程Web服务器(它使用了Java的HttpURLConnection API接口)的代码进行单元测试。我们特别展示了如何使用开源的Jetty来替换远程Web服务器。Jetty 可嵌入的特性让你能专注于替换Jetty的HTTP 请求处理器,而不是替换整个容器。我们通过替换Java的 HttpURLConnection类也阐述了一个更轻量级的解决方案。
下一章将介绍一种叫做mock objects的技术,这种技术支持细粒度单元测试。细粒度单元测试是完全通用的,并且(也是最好的一点)还能迫使你编写优秀的代码。虽然stub在一些情况中非常有用,但是有些人会觉得stub已经有些过时了,在过去多数人都认为测试应该是独立的,并且不应该修改已有的代码。新的mock objects策略不仅允许修改代码,而且还鼓励这一点。使用mock objects 不仅仅是一种单元测试策略,它更是一种编写代码的全新方式。