如何安全地测试需要外部Web API的代码

时间:2016-01-07 12:59:58

标签: java rest unit-testing junit

我即将踏上编写java库以包装Web API的旅程,我希望在此过程中编写测试,以确保一切都很好。我已经使用JUnit很长一段时间了,我很乐意和PowerMockito / Mockito这样的工具一起使用它。然而,我担心如果API关闭或我无法访问它,测试可能会失败,因为我最终计划在CI服务器(travis-ci)上运行它,并希望build-test-deploy过程为尽可能接近自动化。

我已经完成了相当多的谷歌搜索,不幸的是,我在这里发现的大多数问题都是关于测试程序员已经创作或可以在本地设置的API。我知道可以通过一点点的修补来复制API的基本功能,尽管这感觉更像是向前退一步而不是前进。

我目前正在脑海中起草创意,到目前为止,这感觉就像是一种适度可靠的解决方案,但如果有人能够验证这一点或提供更好的解决方案,那就好了。

TestUtil.java

public static boolean isReachable() {
    try (Socket socket = new Socket("api.host.com", 80)) {
        return true;
    } catch (Exception e) {
        return false;
    }
}

TestCase.java

@BeforeClass 
public static void testReachable() {
    Assume.assumeTrue("API was not reachable, test cannot run", TestUtil.isReachable());
}

我只是出于偏执而假设@BeforeClass

但是,这并不能解决HTTP错误,只检查是否有东西在端口80上侦听。是否值得用HEAD请求替换?除了检查错误,我真的不确定。我不愿意在没有确认的情况下使用HTTP,这是最好的方法,因为这个库有可能变得非常大。

修改 我偶然发现了InetAddress#isReachable(),虽然根据一篇文章,我读它并不是最可靠的。

2 个答案:

答案 0 :(得分:5)

您应该区分单元测试和集成测试。

单元测试不应该依赖于网络和文件系统等基础设施。所有这些方面都应该重新构建,例如在单元测试期间被模拟的单独的类或方法中。我总是将单元测试编写为“白盒”测试,我尝试使用代码覆盖工具覆盖代码中的每个可能的流程。

在您的情况下,您可以为项目中的业务逻辑编写单元测试,例如哪些API调用以哪种顺序进行,逻辑规则取决于API调用的结果,可能是一些与内容相关的验证和错误处理,将域对象映射到远程API的协议等。

这只留下实际调用API的部分未经测试。为此,我将运行一个嵌入式Web服务器(例如Jetty),它托管一个提供熟响应的远程API的模拟版本。然后,您可以编写调用此本地服务器的集成测试来检查您的网络代码及其配置。

当我使用像Spring-WS或JAXB这样的框架时,我经常跳过集成测试部分,因为这意味着要做很多工作来测试你的配置,没有必要测试这些框架的代码。这可能只是我懒惰但我总是试图权衡创建测试的努力与预期的好处。

当您拥有复杂的服务环境并且正在进行大量的compex映射,配置和路由时,它就变成了另一个故事。然后,您的集成测试是验证所有服务是否已连接并正确相互通信的最佳方法。我会称之为“黑盒子”测试,您可以根据整个系统的预期功能(例如用户故事)来指定测试,而不依赖于实现细节。

答案 1 :(得分:1)

根据API的大小以及您打算用它做什么,代码(正如您自己所说)可能会变得非常大。在开始您的旅程之前,也许您可​​以评估已经存在的事情,例如RetroFit

还值得一提的是,RetroFit的性质与外部API的对话。它还有tests and is open source。你可以看看他们的测试灵感。