使用文件系统函数测试对象

时间:2010-12-09 16:09:35

标签: php unit-testing filesystems integration-testing

我正在编写一些广泛使用文件系统的对象。我不确定测试它们的正确方法是什么。

我在理论上知道我应该在一些对象中抽象文件系统功能然后模拟它们,但在我的情况下它将毫无意义:我想要测试的类的主要用途是管理文件。所以在测试新对象时我会遇到同样的问题,只需移动一个级别。

我能想到进行测试的唯一方法就是实际使用文件系统。问题是测试将在浏览器和命令行中运行,因此我需要在每个人都具有写访问权限的目录中工作。此外,这似乎不是一个非常便携的解决方案。

有什么想法吗?

4 个答案:

答案 0 :(得分:5)

您可以mock the filesystem with vfsStream作为suggested in the PHPUnit Manual

  

vfsStream是虚拟文件系统的流包装器,可能有助于单元测试模拟真实文件系统[...]如果系统上有PEAR安装程序,则只需执行以下命令: p>

$ pear channel-discover pear.bovigo.org
$ pear install bovigo/vfsStream-beta

examples at GithubWiki

答案 1 :(得分:1)

引入非常低级别的php函数,除了调用文件系统函数之外什么都不做,并在你的代码中使用它们。

然后,在您的测试工具中,使用存根(可能记录它们已被调用)覆盖此功能。这样,您可以验证您的代码将在实时系统中调用正确的低级PHP函数。对于单元测试,你可以做的就是,真的。

答案 2 :(得分:1)

我认为你有三种选择:

  • 接受某些测试作为集成测试更好。通过为测试运行创建一个小世界(在%TEMP%中,基于类/方法名称)开始测试,然后在完成后将其销毁。
  • 检查您的抽象层,并从类中提取文件IO。为此创建一个接口。其余的使用集成测试(但这将非常小)。这不同于上面的内容,而不是做文件。你写了意图,比如说ioThingie.loadSettings()。
  • 模拟IO(按上面Gordon的建议)。

我通常使用混合选项一和二,只使用三个用于边缘情况,因为我在C#中发现模拟原始IO层(System.IO.File)实际上只显示您可以编写模拟语句,并使您的测试有点太依赖于实现,但是上面的vfs看起来像是模拟FS而不是对象。

答案 3 :(得分:1)

另一种变体是模拟使用runkit文件系统的PHP函数。不确定它是最好的解决方案,但它的工作原理。 有phpunit-mockfunction - PHPUnit扩展,简化了模拟PHP函数。

所以例子是:

class Tests extends PHPUnit_Framework_TestCase {
    // ... setUp, tearDown, other tests...

    function test_1(){
        $file_size_to_return = 10;

        $fake_filesize = new PHPUnit_Extensions_MockFunction('filesize', $this->obj->tested_method);
        $fake_filesize->expects($this->once())->will($this->returnValue($file_size_to_return));

        $this->obj->tested_method(); // actually run method we want test that contains filesize() function...
    }
}