0

我正在尝试学习 TDD,我的第一个项目是一个基于 PHP 的项目,以帮助我组织我的小型 MP3 收藏。我知道还有许多其他更好的解决方案,但这只是为了掌握 TDD。

我需要一个接受文件名的方法,并使用命令行调用 ffmpeg 返回 MP3 的持续时间。是否可以在不将其指向真正的 MP3 的情况下测试此方法?我应该只测试简单的东西,例如文件是否存在?我应该费心测试它吗?

我很欣赏你的想法。

提前谢谢了。

编辑:我很抱歉没有提到对 ffmpeg 的调用不是通过类或 API 本身,而是通过 CLI。

$output = shell_exec("{$ffmpeg_exe} -i \"{$file_path}\" 2>&1");

这是我在测试时遇到问题的地方。我认为没有任何方法可以在不使用 Runkit 的情况下模拟它,我想避免这种情况,因为它不能通过 Composer 安装,而且我想避免需要编译的依赖项。

4

2 回答 2

1

这取决于您要称为“单元测试”的内容:)

在我看来,单元测试不应该依赖于被测类之外的任何东西。它绝对不应该发出网络请求、数据库调用或接触文件系统

您描述的测试是我称之为集成或验收测试的测试——编写失败的验收测试通常是我个人 TDD 周期的开始。然后,如果合适,我将其分解为更小的部分并编写一个失败的单元测试,并在多个单元测试上循环 red-green-refactor 直到验收测试通过。

使您的测试更加孤立的另一种方法是使用测试替身(模拟、存根、伪造、间谍等的通用术语)。在您的情况下,这可能是最好的方法——拥有一个模拟对象,其行为类似于与文件系统交互的对象,但您可以控制它以某种方式进行操作。我会有一个参数来传递它,如果没有为此传递任何东西,请使用内置的文件交互库。

我有一段时间没有做 PHP,但这里有一些伪代码:

function duration(filename, filesystem)
  filesystem = PHP File interacting object if filesystem isn't passed in
  file = filesystem.find(filename)
  return file.duration

这样,在您的测试中,您可以执行以下操作:

test that the duration function returns the duration of the file whose name is passed in
  fake_file = stub that returns 3:08 when we call duration on it
  fake_filesystem = stub that returns fake_file when we call find on it with a filename
  assert_equal duration("some_filename.mp3", fake_filesystem), 3:08

再次,超级伪代码!!!祝你好运!!


回复您的编辑:

啊啊啊我明白了。我假设您正在解析$output以提取您想要的信息并处理运行此命令可能返回的任何错误。那,IMO,是你的代码中应该测试的有趣部分。所以我可能会把它shell_exec放在一个我不会打扰测试的函数中,但是在你的解析逻辑测试中,我会存根这个函数的返回值,以便能够测试你在得到各种输出时所做的事情。

我还有至少一个集成或验收测试,它实际上会调用shell_exec并且实际上需要一个文件存在于$file_path.

这一shell_exec行基本上是在做字符串连接,所以不值得测试。TDD 与其说是一种规则,不如说是一种指导,有时你不得不决定不测试:)

于 2013-09-08T21:22:11.357 回答
0

You can stub ffmpeg to not use the real files.

于 2013-09-08T21:28:52.690 回答