如何测试连接到FTP服务器的类?

时间:2012-03-27 18:48:52

标签: delphi unit-testing ftp delphi-2010

我正在为我的应用程序开发实时更新。到目前为止,我已经创建了几乎所有单元测试,但我不知道如何测试连接到FTP服务器并下载新版本的特定类。

要测试此类,我应该创建一个FTP测试服务器并在我的单元测试中使用它吗?如果是这样,我如何确保此FTP服务器始终与我的测试保持一致?我应该在测试开始之前手动创建我需要的每个文件,还是应该在我的测试类中自动执行此操作(拆卸和设置方法)?

这个问题也适用于连接任何类型服务器的单元测试类。

修改

我已经在模拟我的ftp类了,所以我不需要在其他测试中连接到ftp服务器。

让我看看沃伦在评论中所说的话是否正确:

  

我会说,一旦你通过TCP / IP与一个单独的应用程序交谈   我们应该称之为“集成测试”。一个不再测试了   单位或方法,但系统。

当单元测试需要与另一个应用程序(可以是HTTP服务器或FTP服务器)通信时,这不再是单元测试而是集成服务器吗?如果是这样,我是否通过尝试使用单元测试技术来创建此测试?说我不应该对这个班级进行单元测试是否正确?它对我有意义,因为单元测试似乎需要做很多工作。

5 个答案:

答案 0 :(得分:9)

在测试中,目的始终是首先回答这个问题:测试了什么 - 即测试的范围。

因此,如果您正在测试FTP服务器实现,则必须创建FTP客户端。

如果您正在测试FTP客户端,则必须创建FTP服务器。

因此,您必须缩小测试范围,直到达到统一级别。

可能是例如为了您的目的:

  • 获取为应用程序安装的当前文件的列表;
  • 获取远程可用文件的列表;
  • 获取文件更新;
  • 检查文件是否正确(校验和?);
  • 等......

每个测试项目都有一些模拟和存根。有关两者之间的区别,请参阅this article。简而言之(AFAIK),存根只是一个仿真对象,它始终有效。模拟(在每个测试中应该是唯一的)是可能改变测试结果的元素(通过或失败)。

对于FTP连接的确切目的,您可以例如(在测试客户端时)有一些返回文件列表的存根,以及一个模拟器,它将测试FTP服务器的几个可能的问题(超时,连接丢失,内容错误)。然后您的客户端将按预期做出反应。您的模拟可能是一个真正的FTP服务器实例,但它会按预期运行以触发所有潜在的错误。通常,每个错误都会引发一个异常,由测试单元跟踪,以便通过/不通过每个测试。

编写好的测试代码有点困难。测试驱动的方法起初有点耗时,但从长远来看总是更好。这里有一本好书,或者至少是一些参考文章(如上面链接的Martin Fowler)。在Delphi中,使用接口和SOLID原则可以帮助您编写此类代码,并创建存根/模拟来编写测试。

从我的实验中,每个程序员有时会在编写测试时丢失...在某些情况下,良好的测试编写可能比编写功能更耗时...您会收到警告!每项测试都应视为一项功能,并评估其成本:是否值得?这里不是另一种测试更合适吗?我的测试是否与它正在测试的功能分离?它尚未经过测试吗?我是在测试我的代码还是第三方/库功能?

超出主题,但我的两分钱:HTTP / 1.1现在可能是比FTP更好的候选者,即使是文件更新。您可以恢复HTTP连接,并行地通过块加载HTTP内容,并且此协议比FTP更加代理友好。托管一些HTTP内容比FTP更容易(一些FTP服务器也已知安全问题)。目前大多数软件更新都是通过HTTP / 1.1执行的,而不是FTP(例如Microsoft产品或大多数Linux存储库)。

修改

当您使用远程协议时,您可能会争辩说您正在进行集成测试。这可能有意义,但恕我直言,这是不一样的。

据我了解,当您让所有组件与实际应用程序一起工作时,就会进行集成测试,然后检查它们是否按预期工作。我关于FTP测试的建议是你正在模拟FTP服务器,以便明确地测试所有潜在的问题(超时,连接或传输错误......)。这不是集成测试:代码覆盖范围要大得多。而且您只测试代码的一部分,而不是整个代码集成。这不是因为您正在使用某些远程连接进行集成测试:这仍然是单一测试。

当然,集成和系统测试应在单一测试后进行。但FTP客户端单一测试可以模拟FTP服务器,在本地运行它,但测试可能在真正的大型万维网上发生的所有潜在问题。

答案 1 :(得分:5)

如果您使用的是Indy 10的TIdFTP组件,那么您可以利用Indy的TIdIOHandlerStream类假冒FTP连接,而无需实际连接到真正的FTP服务器。

创建一个TStream对象,例如TMemoryStreamTStringStream,其中包含您希望TIdFTP为其发送的所有命令接收的FTP响应(使用数据包嗅探器预先捕获这些数据嗅探器,让您了解需要包含的内容),并将更新文件的副本放在您通常下载到的本地文件夹中。创建TIdIOHandlerStream对象并将TStream指定为其ReceiveStream,然后在调用TIdFTP.IOHandler之前将IOHandler分配给Connect()属性。

例如:

ResponseData := TStringStream.Create(
  '220 Welcome' + EOL +
  ... + // login responses here, etc...
  '150 Opening BINARY mode data connection for filename.ext' + EOL +
  '226 Transfer finished' + EOL +
  '221 Goodbye' + EOL);

IO := TIdIOHandlerStream.Create(FTP, ResponseData); // TIdIOHandlerStream takes ownership of ResponseData by default

FTP.IOHandler := IO;
FTP.Passive := False;  // Passive=True does not work under this setup

FTP.Connect;
try
  FTP.Get('filename.ext', 'c:\path\filename.ext');
  // copy your test update file to 'c:\path\filename.ext'...
finally
  FTP.Disconnect;
end;

答案 2 :(得分:4)

单元测试应该快速,快速闪电。任何减慢它们的东西都会阻止你想要运行它们。

从一次奔跑到另一次奔跑,它们也应该是一致的。测试实际的文件传输会在单元测试中引入随机失败的可能性。

如果您正在测试的类只是包装您正在使用的ftp库的api,那么您已经达到了应用程序的一个边界,您不需要单元测试它。 (好吧,有时候你这样做。它叫做探索性测试,但是一旦你得到你的答案,这些通常会被丢弃)

但是,如果类中有任何逻辑,您应该尝试与实际的api隔离测试它。您可以通过为ftp api创建包装器来完成此操作。然后在单元测试中创建一个测试双,它可以替代包装器。有许多不同名称的变体:stub,fake,mock对象。最重要的是,您要确保您的单元测试与任何外部影响隔离开来。具有零星行为的单元测试不是无用的。

测试实际的文件传输机制应该在集成测试中完成,这通常运行频率较低,因为它较慢。即使在集成测试中,您也希望尽可能地控制测试环境。 (即在配置为模仿生产服务器的本地网络上使用ftp服务器进行测试)。

请记住,你永远不会抓住所有事情。无论测试有多好,错误都会漏掉。只要确保他们这样做,你就可以在下一次添加另一个测试来捕获它们。

我建议购买或查看Gerard Meszaros的XUnit Test Patterns副本。它是关于什么/何时/如何进行单元测试的有用信息的宝库。

答案 3 :(得分:2)

只需借用您喜欢的任何套接字组件(Indy,ICS或其他)附带的FTP或HTTP Server演示。即时测试服务器。

我会将它放入工具文件夹以进行单元测试。我可能会编写一些代码来检查TestFtpServer.exe是否已经存在,如果没有,则启动它。

我会将它从单元测试应用程序的进程内存空间中删除,因此是单独的进程。

请注意,当您进入FTP服务器操作时,单元测试应该被称为“集成测试”。

我不会手动创建单元测试中的文件。我希望我的代码应该从版本控制中检出,然后从批处理文件构建,该文件运行我的测试程序,该程序知道一个名为Tools的子文件夹,其中包含EXE,可能还有一个名为{{的文件夹。 1}}和ServerData可用于保存在服务器上启动并传输到本地单元测试应用程序的数据。也许你可以破解你的演示服务器让它终止一段时间(当你想测试失败时),但我仍然认为你不会得到很好的报道。

注意如果您正在进行自动更新,我认为没有多少单元测试会削减它。您需要处理许多与互联网相关的潜在问题。当您的主机名无法解决时会发生什么?当下载部分通过并失败时会发生什么?自动更新与单元测试的功能不太匹配。

答案 4 :(得分:0)

为知道如何与FTP服务器通信的一个组件编写几个集中的集成测试。对于那些测试,您需要在每次测试之前启动FTP服务器,将测试所需的任何文件放在那里,并在测试关闭服务器之后。

完成后,在所有其他测试中,您将不会使用真正连接到FTP服务器的组件,但您将使用它的假冒或模拟版本(由某些人支持)内存数据结构而不是真实文件和网络套接字)。这样,除了 FTP客户端组件之外,您可以为其他所有编写不需要FTP服务器或网络连接的单元测试。

除了这些测试之外,可能还需要一些端到端测试来启动整个程序(与组件级别的集中测试不同)并连接一个真正的FTP服务器。端到端测试不能涵盖所有极端情况(与单元测试不同),但它们可以help to solve integration issues