在测试该API的包装器时,我的单元测试是否应该直接触摸API?

时间:2008-10-17 20:02:52

标签: unit-testing tdd

我写了一些单元测试 测试FTP服务器API的包装

单元测试和FTP服务器都在同一台机器上。

包装器API部署到我们的平台,并用于远程处理和Web服务方案。包装器API本质上采用XML消息来执行诸如添加/删除/更新用户,更改密码,修改权限......等等任务。

在单元测试中,比如说要将用户添加到虚拟域,我创建要发送到API的XML消息。 API执行它并返回一个响应,其中包含有关操作是成功还是失败的状态信息(错误代码,验证失败等)。

要验证API包装器代码是否确实做了正确的事情(如果响应指示成功),我调用FTP服务器的COM API并直接查询其存储以查看是否,例如,在创建用户帐户时,用户帐户确实已经创建了。

这味道不好吗?

更新1: @ Jeremy / Nick:包装器是测试的重点,FTP服务器及其COM API是第三方产品,可能经过良好测试和稳定。包装器API必须解析XML消息,然后调用FTP服务器的API。我如何验证,这可能是一个愚蠢的情况,包装器正确设置了用户帐户的特定属性。例如,由于包装器代码中的拼写错误而设置了FTP帐户的错误属性或属性。一个很好的例子是设置上传和下载速度限制,这些可以在包装器代码中转换。

更新2:感谢大家的答案。对于那些建议使用模拟的人来说,它已经超出了我的想法,但光线还没有在那里开启,我仍然在努力让我的头脑如何让我的包装器与模拟FTP服务器一起工作。模拟驻留在哪里,我是否将所述模拟的实例传递给包装器API而不是调用COM API?我知道嘲笑但是很难理解它,主要是因为我发现大多数的例子和教程都是如此抽象而且(我很惭愧地说)接近这个难以理解的事情。

8 个答案:

答案 0 :(得分:7)

你好像是混合单位&组件测试问题。

  • 如果您对包装器进行单元测试,则应使用模拟FTP服务器,而不涉及实际的服务器。好的一面是,你通常可以实现这样的100%自动化。
  • 如果您正在对整个事物(包装器+ FTP服务器一起工作)进行组件测试,请尝试在与测试相同的级别验证结果,即通过包装器API。例如,如果发出上载文件的命令,则发出命令以删除/下载该文件以确保文件已正确上载。对于更复杂的操作,测试结果并非易事,那么请考虑使用您提到的COM API“后门”或者可能需要进行一些手动验证(所有测试都需要自动化吗?)。

答案 1 :(得分:3)

  

要验证API包装器代码是否确实做了正确的事情(如果响应指示成功),我调用FTP服务器的COM API

停在那儿。您应该模拟FTP服务器,并且包装器应该对模拟进行操作。

如果您的测试同时运行包装器和FTP服务器,则不是单元测试。

答案 2 :(得分:3)

要使用模拟对象测试包装器,可以执行以下操作:

  • 编写与FTP服务器的COM API具有相同接口的COM对象。这将是你的模拟对象。您应该能够通过依赖注入将接口指针传递给您的包装器来交换真正的FTP服务器和模拟对象。
  • 您的模拟对象应该基于在其接口上调用的方法(模仿FTP服务器API)以及基于所使用的参数值来实现硬编码行为:
  • 例如,如果您使用UploadFile方法,则可以盲目地返回成功结果,并可能存储以字符串数组传入的文件名。
  • 当您遇到包含“错误”的文件名时,您可以模拟上传错误。
  • 当您遇到文件名为“slow”时,您可以模拟延迟/超时。
  • 稍后,DownloadFile方法可以检查内部字符串数组,以查看具有该名称的文件是否已“上传”。

某些测试用例的伪代码是:

//RealServer theRealServer;
//FtpServerIntf ftpServerIntf = theRealServer.getInterface();

// Let's test with our mock instead
MockServer myMockServer;
FtpServerIntf ftpServerIntf = myMockServer.getInterface();

FtpWrapper myWrapper(ftpServerIntf);

FtpResponse resp = myWrapper.uploadFile("Testing123");
assertEquals(FtpResponse::OK, resp);

resp = myWrapper.downloadFile("Testing123");
assertEquals(FtpResponse::OK, resp);

resp = myWrapper.downloadFile("Testing456");
assertEquals(FtpResponse::NOT_FOUND, resp);

resp = myWrapper.downloadFile("SimulateError");
assertEquals(FtpResponse::ERROR, resp);

我希望这会有所帮助......

答案 3 :(得分:2)

我同意Nick和Jeremy关于不接触API的观点。我会嘲笑API
http://en.wikipedia.org/wiki/Mock_object

如果是.NET,您可以使用:
Moq:http://code.google.com/p/moq/

还有一堆其他模拟库。

答案 4 :(得分:0)

您正在测试包装器或API。 API应该按原样运行,因此您不需要对其进行测试。将测试工作集中在包装器上并假装API不存在,当我编写一个执行文件访问的类时,我不会在streamreader中对构建进行单元测试...我专注于我的代码。

答案 5 :(得分:0)

我想说在测试时,您的API应该像数据库或网络连接一样对待。不要测试它,它不在你的控制之下。

答案 6 :(得分:0)

这听起来不像是在问“我应该测试 API吗?” - 你问“我应该使用API​​来验证我的包装器是否做得对吗?”

我说是的。您的单元测试应断言您的包装器传递API报告的信息。例如,在您给出的示例中,我不知道您将如何避免触及API。所以我觉得它闻起来不好。

答案 7 :(得分:0)

我唯一能想到如果更高级别的API是只写的话,何时可以使用更低级别的API来验证结果。例如,如果您可以使用高级API创建用户,那么应该有一个高级API来获取用户帐户。使用它。

其他人建议嘲笑低级API。如果你能做的话,这很好。如果低级组件被模拟,检查模拟以确保设置正确的状态应该没问题。