问题 PHPUnit:我如何模拟这个文件系统?


请考虑以下方案(这不是生产代码):

 class MyClass {
    public function myMethod() {
        // create a directory
        $path = sys_get_temp_dir() . '/' . md5(rand());
        if(!mkdir($path)) {
            throw new Exception("mkdir() failed.");
        }

        // create a file in that folder
        $myFile = fopen("$path/myFile.txt", "w");
        if(!$myFile) {
            throw new Exception("Cannot open file handle.");
        }
    }
}

对,那有什么问题?代码覆盖率报告此行未涵盖:

throw new Exception("Cannot open file handle.");

这是正确的,但由于我在逻辑上创建了上面的文件夹,所以似乎不可能 fopen() 失败(除非在极端情况下,如100%的磁盘)。

我可以忽略代码覆盖中的代码但这有点作弊。有什么方法可以模拟文件系统,以便它可以识别 myFile.txt 并模拟文件系统无法创建文件?


1837
2017-08-23 00:15


起源



答案:


vfsStream 是一个 stream wrapper 为一个 virtual filesystem 这在模拟真实文件系统的单元测试中很有用。你可以从中安装它 作曲家

更多信息:

https://github.com/mikey179/vfsStream

https://phpunit.de/manual/current/en/test-doubles.html


9
2017-08-23 00:23



我希望mkdir()通过并使用vfs使fopen()失败,但是如何在没有两个单独函数的情况下进行设置? - Elliot Chance
检查 Mocking the Filesystem 特别是从例子开始 10.15 在里面 phpunit.de 链接上面。使用vfs的优点是原始文件系统没有实际的依赖关系。 - raidenace


答案:


vfsStream 是一个 stream wrapper 为一个 virtual filesystem 这在模拟真实文件系统的单元测试中很有用。你可以从中安装它 作曲家

更多信息:

https://github.com/mikey179/vfsStream

https://phpunit.de/manual/current/en/test-doubles.html


9
2017-08-23 00:23



我希望mkdir()通过并使用vfs使fopen()失败,但是如何在没有两个单独函数的情况下进行设置? - Elliot Chance
检查 Mocking the Filesystem 特别是从例子开始 10.15 在里面 phpunit.de 链接上面。使用vfs的优点是原始文件系统没有实际的依赖关系。 - raidenace


是!

您应该以某种方式注入完整路径,并且不要在该方法中调用sys_get_temp_dir()。

任何不存在的路径都应该引发问题。你不需要VFS。

但是,在触发异常之前,您将获得E_NOTICE(或者可能是警告?)。所以你应该首先检查is_writable,如果它返回false则抛出异常。


2
2017-08-23 00:23



在这种情况下,基本路径是无关紧要的,无论我是否注入它。 - Elliot Chance
这是相关的。使此失败的最简单,一致的方法是更改​​基本路径。同 sys_get_temp_dir 您不能使用VSF,因为该基本路径始终是真正的路径。 - Evert


您还可以将函数分解为2个方法,一个用于创建路径,另一个用于使用它。然后,可以进行单独测试以确保创建路径。当您尝试使用错误路径时,第二组测试可以检查并捕获异常。


2
2017-08-28 20:03