对文件系统进行模仿
对文件系统进行模仿
vfsStream 是对虚拟文件系统 的 流包覆器(stream wrapper),可以用于模仿真实文件系统,在单元测试中可能会有所助益。
如果使用 Composer 来管理项目的依赖关系,那么只需简单的在项目的 composer.json
文件中加一条对 mikey179/vfsStream
的依赖关系即可。以下是一个最小化的 composer.json
文件例子,只定义了一条对 PHPUnit 4.6 与 vfsStream 的开发时(development-time)依赖:
{
"require-dev": {
"phpunit/phpunit": "~4.6",
"mikey179/vfsStream": "~1"
}
}
Example 9.21, “一个与文件系统交互的类”展示了一个与文件系统交互的类。
Example 9.21. 一个与文件系统交互的类
<?php
class Example
{
protected $id;
protected $directory;
public function __construct($id)
{
$this->id = $id;
}
public function setDirectory($directory)
{
$this->directory = $directory . DIRECTORY_SEPARATOR . $this->id;
if (!file_exists($this->directory)) {
mkdir($this->directory, 0700, TRUE);
}
}
}?>
如果不使用诸如 vfsStream 这样的虚拟文件系统,就无法在隔离外部影响的情况下对 setDirectory()
方法进行测试(参见 Example 9.22, “对一个与文件系统交互的类进行测试”)。
Example 9.22. 对一个与文件系统交互的类进行测试
<?php
require_once 'Example.php';
class ExampleTest extends PHPUnit_Framework_TestCase
{
protected function setUp()
{
if (file_exists(dirname(__FILE__) . '/id')) {
rmdir(dirname(__FILE__) . '/id');
}
}
public function testDirectoryIsCreated()
{
$example = new Example('id');
$this->assertFalse(file_exists(dirname(__FILE__) . '/id'));
$example->setDirectory(dirname(__FILE__));
$this->assertTrue(file_exists(dirname(__FILE__) . '/id'));
}
protected function tearDown()
{
if (file_exists(dirname(__FILE__) . '/id')) {
rmdir(dirname(__FILE__) . '/id');
}
}
}
?>
上面的方法有几个缺点:
-
和任何其他外部资源一样,文件系统可能会间歇性的出现一些问题,这使得和它交互的测试变得不可靠。
-
在
setUp()
和tearDown()
方法中,必须确保这个目录在测试前和测试后均不存在。 -
如果测试在
tearDown()
方法被调用之前就终止了,这个目录就会遗留在文件系统中。
Example 9.23, “在对与文件系统交互的类进行的测试中模仿文件系统”展示了如何在对与文件系统交互的类进行的测试中使用 vfsStream 来模仿文件系统。
Example 9.23. 在对与文件系统交互的类进行的测试中模仿文件系统
<?php
require_once 'vfsStream/vfsStream.php';
require_once 'Example.php';
class ExampleTest extends PHPUnit_Framework_TestCase
{
public function setUp()
{
vfsStreamWrapper::register();
vfsStreamWrapper::setRoot(new vfsStreamDirectory('exampleDir'));
}
public function testDirectoryIsCreated()
{
$example = new Example('id');
$this->assertFalse(vfsStreamWrapper::getRoot()->hasChild('id'));
$example->setDirectory(vfsStream::url('exampleDir'));
$this->assertTrue(vfsStreamWrapper::getRoot()->hasChild('id'));
}
}
?>
这有几个优点:
-
测试本身更加简洁。
-
vfsStream 让开发者能够完全控制被测代码所处的文件系统环境。
-
由于文件系统操作不再对真实文件系统进行操作,
tearDown()
方法中的清理操作不再需要了。