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

Java 如何安全地测试需要外部web API的代码,java,rest,unit-testing,junit,Java,Rest,Unit Testing,Junit,我即将开始编写一个java库来包装一个web API的旅程,我希望在此过程中编写测试,以确保一切顺利。我已经使用JUnit很长一段时间了,我很乐意将它与PowerMockito/Mockito等工具一起使用。但是,我担心,如果API关闭或我无法访问它,测试可能会失败,因为我最终计划在CI服务器(travis CI)上运行它,并且希望构建测试部署过程尽可能接近自动化 我在谷歌上搜索了不少,不幸的是,我在这里发现的大多数问题都是关于测试程序员编写的或可以在本地设置的API。我知道只要稍加修改就可以复

我即将开始编写一个java库来包装一个web API的旅程,我希望在此过程中编写测试,以确保一切顺利。我已经使用JUnit很长一段时间了,我很乐意将它与PowerMockito/Mockito等工具一起使用。但是,我担心,如果API关闭或我无法访问它,测试可能会失败,因为我最终计划在CI服务器(travis CI)上运行它,并且希望构建测试部署过程尽可能接近自动化

我在谷歌上搜索了不少,不幸的是,我在这里发现的大多数问题都是关于测试程序员编写的或可以在本地设置的API。我知道只要稍加修改就可以复制API的基本功能,尽管这感觉更像是倒退而不是前进

我目前正在脑子里构思一些想法,到目前为止,这似乎是一个中等可靠的解决方案,不过如果有人能够验证这一点或提供更好的解决方案,那就太好了

TestUtil.java

TestCase.java

我假设上课前有
@BeforeClass
只是出于偏执

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

编辑:
我刚刚偶然发现了
InetAddress#isReachable()
,尽管根据我正在阅读的一篇文章,它不是最可靠的

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

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

在您的案例中,您可以为项目中的业务逻辑编写单元测试,比如按哪个顺序进行哪些API调用,根据API调用的结果制定逻辑规则,可能是一些与内容相关的验证和错误处理,将域对象映射到远程API的协议等

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

当我使用SpringWS或JAXB这样的框架时,我经常跳过集成测试部分,因为这意味着要做大量工作来测试您的配置,而不需要真正测试这些框架的代码。这可能只是我的懒惰,但我总是试图权衡创建测试的努力与预期的好处


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

根据API的大小和您打算使用它做什么,代码(正如您自己所说)可能会变得相当大。在开始你的旅程之前,也许你可以评估一些已经存在的东西来这样做


还值得一提的是,根据其与外部API对话的性质进行的改进。它也有。您可以查看他们的测试以获得灵感。

根据API的大小和您打算使用它做什么,代码(正如您自己所说)可能会变得相当大。在开始您的旅程之前,也许您可以评估一些已经存在的东西来完成这项工作,比如改型。同样值得一提的是,改型的本质是它与外部API的对话。它也有测试,并且是开源的。你可以从他们的测试中寻找灵感。哦,这也是方形的,太棒了-谢谢。啊,你提出了一个关于单元测试和集成测试的非常好的观点,我的错。只要工作有回报,我非常乐意尝试一下,我会看看模仿API能让我走多远。从jetty开始,您是否有任何推荐的资源,或者标准文档(我假设它有一些)是否可以做得很好?我在这里要做的一个评论是,我通常还编写一个“外部”集成测试,只点击服务以验证它是否启动、URL是否仍然有效,以及结果是否按预期格式化。然后,我只是偶尔(像每晚)运行这个测试,这样如果服务发生变化,我就会提前知道。如果可能的话,我会针对服务的集成/测试版本编写此测试。谢谢John,我完全可以设置类似的东西!
public static boolean isReachable() {
    try (Socket socket = new Socket("api.host.com", 80)) {
        return true;
    } catch (Exception e) {
        return false;
    }
}
@BeforeClass 
public static void testReachable() {
    Assume.assumeTrue("API was not reachable, test cannot run", TestUtil.isReachable());
}