我一直在兜圈子,试图找出对我正在开发的API客户端库进行单元测试的最佳方法。该库具有一个Client
基本上与API进行1:1映射的Wrapper
类,以及一个额外的类,该类在的顶部提供了更加用户友好的界面Client
。
Wrapper --> Client --> External API
我首先针对Client
和编写了一系列测试Wrapper
,实际上只是测试它们是否转发到操作的任何适当功能(Wrapper
在上操作Client
,并Client
在HTTP连接上操作)。但是,我开始对此感到不舒服,因为我感觉自己正在测试这些类的实现,而不是接口。从理论上讲,我可以将这些类更改为具有另一个完全有效的实现,但是我的测试将失败,因为未调用我希望调用的函数。对我来说,这听起来像是脆弱的考验。
之后,我考虑了类的接口。测试应该验证类是否确实完成了其应做的工作,而不是他们是如何完成的。那我该怎么做呢?首先想到的是对外部API请求进行存根。但是,我担心过度简化外部服务。我见过的很多存根API的示例都给出了罐头响应,这听起来像是一种非常简单的方法,可以仅测试您的代码是否针对假API正确运行。另一种方法是模拟服务,这是不可行的,并且每当真实服务发生变化时就需要保持最新状态-感觉像是过分杀伤和浪费时间。
最后,我从程序员SE的另一个答案中读取了此内容:
远程API客户端的工作是发出某些调用-不多也不少。因此,它的测试应验证它是否发出了这些呼叫-不多也不少。
现在,我或多或少地确信-测试时Client
,我需要测试的是它向API发出了正确的请求(当然,总有API会更改但我的测试继续通过的可能性-但这就是集成测试很有用的地方)。由于Client
与API只是1:1的映射,因此在将一个有效实现更改为另一个之前,我的担心并没有真正适用-的每种方法只有一个有效实现Client
。
但是,我仍然坚持Wrapper
上课。我看到以下选项:
我对
Client
类进行存根处理,然后测试是否调用了适当的方法。这样,我做的与上述相同,但是将其Client
作为API的替代。这使我回到了起点。再一次,这给了我测试实现而不是界面的不舒服的感觉。将Wrapper
很可能使用了完全不同的客户端实现。我创建一个模拟
Client
。现在,我必须决定对它进行模拟的程度-创建服务的完整模拟将花费很多精力(比库本身要付出更多的工作)。API本身很简单,但是服务却很复杂(本质上是一个对数据进行操作的数据存储)。再说一次,我将必须使模拟与real保持同步Client
。我只是测试是否正在发出适当的HTTP请求。这意味着
Wrapper
将通过一个真实的Client
对象进行调用以发出这些HTTP请求,因此我并不是在单独测试它。这使得它有点可怕的单元测试。
因此,我对这些解决方案都不满意。你会怎么做?有正确的方法去做吗?