Модульное тестирование приложений, использующих файловую систему

Для примера возьмем ситуацию:
у пользователя в профайле есть аватар – либо собственный если присутсвует файл userId.png, либо аватар по умолчанию:

<?php
$avatarPath = $this->baseUrl('/images/avatars/' . $this->userId . '.png');
if(!file_exists($_SERVER['DOCUMENT_ROOT'] . $avatarPath)) {
    $avatarPath = $this->baseUrl('/images/avatars/default.png');
}
?>
<img src="<?php echo $avatarPath; ?>" alt="avatar"></img>

В данном случае логика отображения зависит от наличия или отсутсвия в файловой системе того или иного файла. Эту зависимость в тестах надо устранить. На помощь приходит виртуальная файловая система и wrapper к ней: vfsStream
С помощью данного streamWrapper’a мы полностью исключаем зависимость тестовой от файловой системы.
Пример теста:

    require_once 'vfsStream/vfsStream.php';
 
    private function setUp()
    {
        // prepare vfs
        vfsStreamWrapper::register();
        vfsStreamWrapper::setRoot(new vfsStreamDirectory('document_root'));
        $_SERVER['DOCUMENT_ROOT'] = vfsStream::url('document_root');
        // create test data
        $avatarPath = 'images/avatars/77.png';
        mkdir($_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . dirname($avatarPath), 777, true);
        $fp = fopen($_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . $avatarPath, 'w');
        fclose($fp);
    }
 
    public function testGetDefaultAvatar()
    {
        $this->dispatch('/user/avatar/id/10');
        $this->assertXpath("//img[@src = '/images/avatars/default.png']");
    }
 
    public function testGetCustomAvatar()
    {
        $this->dispatch('/user/avatar/id/77');
        $this->assertXpath("//img[@src = '/images/avatars/77.png']");
    }

В заключение следует добавить, что есть случаи в которых vfsStream не поможет, из-за ограничений php-шных stream wrapper’ов.

Leave a Reply