我正在尝试学习TDD,我的第一个项目是一个基于PHP的项目,帮助我组织一些有点小的MP3收藏。我知道还有很多其他更好的解决方案,但这只是为了掌握TDD。
我需要一个接受文件名的方法,并使用命令行调用ffmpeg返回MP3的持续时间。是否可以测试这种方法,而不是将其指向真正的MP3?我应该只测试简单的事情,比如文件是否存在?我应该费心去测试吗?
我很感激你的想法。
非常感谢提前。
编辑:我很抱歉没有提到对ffmpeg的调用不是通过类或API本身,而是通过CLI。
$output = shell_exec("{$ffmpeg_exe} -i \"{$file_path}\" 2>&1");
这是我在测试时遇到的问题。我不认为有没有办法在不使用Runkit的情况下模拟它,我想避免使用它,因为它无法通过Composer安装,我想避免需要编译的依赖项。
答案 0 :(得分:1)
这取决于你想称之为“单元测试”:)
在我看来,单元测试不应该依赖于被测课程之外的任何东西。绝对不应该进行网络请求,数据库调用或触摸文件系统。
您描述的测试是我称之为集成或验收测试的测试 - 编写失败的验收测试通常是我个人TDD周期的开始。然后,如果合适的话,我将其分解成更小的部分,并编写一个失败的单元测试,并在多个单元测试中循环红绿重构,直到验收测试通过。
使测试更加孤立的另一种方法是使用测试双打(模拟,存根,假货,间谍等的通用术语)。在您的情况下,这可能是最好的方法 - 让一个像对象一样的模拟对象与文件系统交互,但您可以控制以某种方式操作。我会有一个参数来传递它,如果没有传递任何内容,请使用内置的文件交互库。
我有一段时间没有完成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
再次,超伪代码!祝你好运!!
对您的修改的回复:
Aaahhh我明白了。我假设您正在解析$output
以提取所需的信息并处理运行此命令可能返回的任何错误。那个,IMO,是你应该测试的代码中有趣的部分。所以我可能会将shell_exec
放在一个我不打扰测试的函数中,但是在你的解析逻辑的测试中,我会将这个函数的返回值存根,以便能够测试你在做什么时你得到各种输出。
我还会进行至少一次实际调用shell_exec
的集成或验收测试,并且实际上需要$file_path
处的文件。
这条shell_exec
行基本上是在进行字符串连接,所以它不值得测试。 TDD并不是一个规则作为指导,有时有时你必须决定不测试:)
答案 1 :(得分:0)
你可以将ffmpeg存根为不使用真实文件。