在进行Java测试时,我应该模拟客户端还是模拟服务器?

3
在客户端服务器架构中,当应该模拟客户端和应该模拟服务器时,最好的方法是什么?我知道单元测试应该只测试给定类,并将每个依赖对象都模拟,而集成测试应该测试整个功能。当涉及到API调用时,我很困惑:我应该模拟我用于API调用的客户端,还是使用一些服务器模拟框架并让真正的客户端调用模拟服务器。
我有一个情况,我应该(不是强制性的)测试是否命中了正确的API URL,并且传递了查询参数或请求体中的特定值。通过模拟客户端,我可以简单地“验证”是否传递了给定参数(路径、方法、请求体),并认为测试成功。如果我要模拟服务器,那么我需要在模拟服务器上创建一些处理来检查路径、方法和请求体是否正确传递并返回一个值。在这种情况下,服务器响应是我可以用来衡量测试是否成功的唯一东西(如果未收到所需数据,则发送500)。
根据您的经验,在客户端服务器架构的集成测试中,测试调用的适当方式是什么?如果我们按照书本上的说法,那么应该使用服务器模拟,但在上述情况下,这是否实际可行?对于单元测试,使用模拟是清楚的。
更新:为避免混淆:我正在制作一个依赖于公共可用服务的客户端,我无法控制该服务。因此,我正在测试客户端是否正常工作,重点在于客户端。问题与我是否(在集成测试中)模拟负责远程连接的客户端对象有关(在我的情况下是Play框架的WSClient),还是应该使用一些服务器模拟(如okhttp模拟Web服务器)。
另一个更新:大多数人建议遵循简单的经验法则:如果这些是单元测试,则模拟客户端;如果这些是集成测试,则使用模拟服务器。现在,我对这种情况很好奇:我有一个A类,它依赖于B类,而B类具有负责远程调用的客户端对象。如果我要为A类编写单元测试,我应该模拟B类,这很好。但是,如果我正在进行A类的集成测试,那么在B类中模拟客户端对象并“验证”是否向其传递了正确的参数(路径、方法和请求体),或者出于完整性考虑,即使模拟客户端对象更容易,我也应该运行模拟服务器。在这种情况下,我将不会测试超时和低级网络错误。或者,在这种情况下,整个集成测试的重点应该是测试网络连接。

当前测试是为哪个组件编写的?在这种情况下,“服务器”是一个非常流动的概念。您的服务器组件可能正在使用其他HTTP服务,从而成为客户端,因此对于模拟服务器来说是有意义的。如果测试的重点是客户端,则可以模拟服务器。在这里,您的问题变得有点不清楚。但是,如果关注的是模拟应该测试的系统组件,那么也许您应该研究服务虚拟化工具,使用代理(mock-server、hoverfly等)来存根外部请求。 - ernest_k
我倾向于使用JUnit来驱动非平凡测试,这些测试是最小可测试单元(即使这意味着在进程中运行客户端和服务器)。 - Peter Lawrey
我在问题中可能应该更清楚地定义一下:我正在制作一个依赖于公开可用服务的客户端,而这个服务我无法控制。因此,我正在测试客户端是否正常工作,并且重点关注的是客户端。 - Dusan Kostic
1个回答

4
你需要:
  1. 集成测试 - 使用像Wiremock这样的存根服务器,测试真实场景,如超时、格式错误的响应、500等。
  2. 测试客户端类 - 使用Mockito模拟服务器端点并验证响应。

好的,你建议集成测试的目的应该是测试网络连接性和服务器可能发送的各种响应。对于第二点,我不太明白你所说的测试客户端类的意思:你是指单元测试(在这种情况下,服务器模拟没有太多意义),还是指另一种类型的测试,在这种测试中,我只需要验证我发送的内容? - Dusan Kostic
你最初询问如何检查客户端是否使用参数正确地命中了API端点。答案是:只需使用Mockito模拟此端点,我不会告诉你如何做,因为我不知道你正在使用哪些框架。这将成为客户端类的单元测试。使用存根服务器,您可以进行真正的端到端测试。在我看来,这是必要的,也是集成测试。我有帮助吗? - niemar
感谢您的回答。一般来说,我的问题与哪种方法更受欢迎有关:模拟客户端调用还是模拟服务器。如何做到这一点不是问题的一部分。大多数人建议遵循简单的经验法则:如果这些是单元测试,则模拟客户端;如果这些是集成测试,则使用模拟服务器。我将更新问题以使其更加精确。 - Dusan Kostic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接