针对REST服务器测试REST客户端。夹具怎么做?


10

在编写单元测试时,通常使用固定装置:可测试的数据很少,因此我们可以说:1.让所有客户都应该包括Willy Wonka。2.删除客户端3,现在获取客户端不应再包括Willy Wonka。

单元测试很好。使用设置/拆卸来重新加载固定装置或回滚事务。因此,测试可以在事务内部完成创建,更新和删除操作。新的临时数据仅持续测试时间,然后被重置。

但是,当我们将REST服务器与REST客户端分离时该怎么办?

我们要确保REST客户端不仅正确读取,而且正确创建,更新和删除。

对于如何针对远程测试REST服务器执行此操作,我找不到任何示例或建议

假设我有一个仅测试灯具的测试REST服务器。HTTP的整个无状态性质意味着很难发送“ BEGIN TRANSACTION”和“ ROLLBACK TRANSACTION”或“ RELOAD FIXTURES”类型的消息,对吗?

我不能成为第一个这样做的人,所以我觉得我需要以不同的方式来思考这个问题。

有什么建议么?


也许,因为它是测试服务器,所以您可以拥有一个可以重新加载固定装置的端点?
David Radcliffe

如果您的主要问题是使测试服务器恢复到预定义状态,那么为什么不为其余API添加某种特殊的测试功能(如“ RELOAD TESTDATA”)来执行您想要的操作呢?当然,您应确保生产中不提供此类API调用。
布朗

Answers:


7

理想情况下,软件系统具有明确定义的系统边界和它们之间的接口。REST服务就是很好的例子。

为此,我建议您不要做您想做的事情。

特别:

我们要确保REST客户端不仅正确读取,而且正确创建,更新和删除。

我建议的是:

  • 在给定特定的输入和输出的情况下,为您的REST客户端构建测试,以确保其行为正确。考虑好(预期)和坏(意外)值。

  • 为您的REST服务构建测试(如果可以控制的话),以根据其预期功能运行

  • 将测试保持在其问题领域附近,以便它们可以帮助指导设计和开发在此情况下重要的内容


3
您在这里很随意地忽略了集成测试的整个想法。我认为这种方法并非来自实践。
2013年

感谢所有有用的建议。另外,在Twitter上,我还提出了一些很棒的建议来尝试使用Ruby gem“ webmock”,并且类似地模拟REST API服务器响应。我也同意“觉得”,我所描述的似乎更多是集成测试,因此我将分别进行研究。再次感谢大家。-德里克
sivers

模拟API是解决问题的好方法。但是,如何确定模拟的API ==真实的API?
FrEaKmAn 2015年

4

这里要记住两个角度:

  • 您在测试代码还是管道?假设您使用的是众所周知的服务和客户端堆栈,则可以安全地设定其测试人员,成千上万的用户通常将确保基础中没有基本的错误。
  • 为什么您的测试不是幂等的?提供一种写入非生产数据或写入其他端点的方法。选择一些可预测的命名模式。在测试之前预加载其余服务器数据库。可能还有更多方法可以实现这一目标-方法确实是战术性的,应取决于应用程序的性质。


1

正如其他人所说,如果要测试客户端,则无需在服务器上进行创建,删除等操作。很多时候,您甚至根本不需要模拟服务器。无论是用Ruby,Python,PHP还是其他语言编写,您实际上只需要确保做出正确的请求并正确处理响应,有时您的客户端可能会使用HTTP库中的方法来进行一个请求,就足以模拟该方法,检查其调用方式并返回测试结果。

假设一个urllib2用于发出请求的Python客户端。您可能在客户端中有一些方法,我们称之为get(),其中有一个urllib2.Request()对它的调用。您只需要模拟对自己班级的调用即可get()

@patch('your.Client.get')
def test_with_mock(self, your_mock):
    your_mock.return_value({'some': 'json'})
    test_obj = your.Client.get_object(5)
    your_mock.assert_called_with('/the/correct/endpoint/5')

这个非常简化的示例使用Python的Mock库来测试一个假设your.Client类,该get_object()方法使用一种生成正确url 的方法来从某些API中获取信息。为了发出请求,客户端get()使用该URL 调用其方法。在此,该方法被模拟(your.Client.get被“修补”,使其处于的控制之下your_mock),并且测试检查是否请求了正确的端点。

模拟方法返回your_mock.return_value客户端必须处理的已配置的JSON响应(),您将进一步声明以测试其是否以预期的方式处理了预期的数据。


但是,当您提出“正确”请求时,您如何确定它是实际的(生产中的)正确请求呢?因为如果我理解您的建议,如果API更改或中断,您的测试仍然可以进行。在生产过程中,情况完全不同。
FrEaKmAn 2015年

1

您所描述的是一个集成测试方案。这些通常很难设置和拆除。它使它们运行缓慢,并且经常很脆。

使用fixture的方法虽然笨拙又笨拙,但这是某些框架(例如Rails)使用的默认方法,并且已经受支持。他们需要抽象测试用例或类似的东西来准备带有夹具的数据库。(请注意,在Rails中测试类别的命名异常,使用DB固定装置的单元测试严格来说也是集成测试。)

我要解决您的情况的方法是接受对API应用程序状态或其数据库进行测试专用的控制。您可以具有其他端点来进行设置和拆卸,这些端点仅在测试环境中存在。或者,您可以与应用程序/ API背后的数据库(或您正在使用的任何数据库)对话。

如果您觉得这太过费力(在不适当的意义上),请考虑使用带有数据库固定装置的方法可以做到这一点:使用其他特定于测试的方法来操纵数据库或应用程序状态。

我认为此讨论与HTTP的无状态本质无关。在大多数情况下,HTTP是无状态的,但应用程序绝对不是。听起来有点像您在寻找REST严格性的地方。您也可以使所有资源都是完全可创建,可读和可删除的。在这种情况下,您可以通过常规API手段进行所有设置和拆卸。但是,实际上通常不会这样做,因为您不希望从业务对应用程序的了解中包括某些操作,至少不是在测试环境之外。


1

猴子补丁

在我的工作中,我们通过使用现有的xUnit框架以及在客户端和服务器之间进行猴子修补网络调用来进行ATDD。在相同的处理空间中,我们加载客户端,然后猴子将网络调用修补到REST服务器堆栈代码的顶部。然后,从客户端发出所有调用,就像通常一样,然后服务器代码完全按照正常出现的方式获取请求。

好处

  • 无需与服务器启动同步(因为没有服务器)
  • 利用经典的单元设置和拆卸方法来管理固定装置
  • 使用模拟/存根和其他猴子补丁进行测试的更细粒度控制的能力
  • 可以使用xUnit框架编写

权衡

  • 不公开多进程的交互/问题(锁定,资源匮乏等)
  • 不暴露多服务器问题(数据序列化,集群样式)
  • 不会暴露网络问题,因为它是模拟的(访问,超时错误等)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.