Search code examples
phptestingphpspecvfs-stream

phpspec testing file contents / file operations


I'm curious about the best way of speccing classes that handle file operations.

Assuming I have a fictional class with a method duplicate whose job is to duplicate the contents of a file.

<?php

class FileOperator
{
    public function duplicate($filename)
    {
        $content = file_get_contents($filename);
        file_put_contents($filename, $content.$content);
    }
}

I know that I can use something like vfsStream to assert the change without touching the actual filesystem (at least with assertions in PHPUnit).

How could I assert that in a spec? Or would it be approached differently?

Also, I get that I might want to extract that functionality into another class and use a Spy to assert that the FileOperator calls its dependency correctly, but then I'd still have to spec that adapter class, and my question remains.

Thanks.


Solution

  • This is more likely a functional test rather than an unit test, so it's hard to use phpspec in this case.

    If you insist, I see two options.

    If you happen to need a method to fetch the file contents too, you could write your spec this way:

    use org\bovigo\vfs\vfsStream;
    use org\bovigo\vfs\vfsStreamDirectory;
    use PhpSpec\ObjectBehavior;
    
    class FileOperatorSpec extends ObjectBehavior
    {
        /**
         * @var vfsStreamDirectory
         */
        private $workDir;
    
        function let()
        {
            $this->workDir = vfsStream::setup('workDir');
        }
    
        function it_duplicates_a_content_in_a_file()
        {
            $this->createFile('foo', 'bar');
    
            $this->duplicate('vfs://workDir/foo');
    
            $this->read('vfs://workDir/foo')->shouldReturn('barbar');
        }
    
        private function createFile($path, $content)
        {
            $file = vfsStream::newFile($path);
            $file->setContent($content);
    
            $this->workDir->addChild($file);
        }
    }
    

    Alternatively, you could use the expect helper:

    use org\bovigo\vfs\vfsStream;
    use org\bovigo\vfs\vfsStreamDirectory;
    use PhpSpec\ObjectBehavior;
    
    class FileOperatorSpec extends ObjectBehavior
    {
        /**
         * @var vfsStreamDirectory
         */
        private $workDir;
    
        function let()
        {
            $this->workDir = vfsStream::setup('workDir');
        }
    
        function it_duplicates_a_content_in_a_file()
        {
            $this->createFile('foo', 'bar');
    
            $this->duplicate('vfs://workDir/foo');
    
            expect(file_get_contents('vfs://workDir/foo'))->toBe('barbar');
        }
    
        private function createFile($path, $content)
        {
            $file = vfsStream::newFile($path);
            $file->setContent($content);
    
            $this->workDir->addChild($file);
        }
    }