1

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.

Adam
  • 5,091
  • 5
  • 32
  • 49

1 Answers1

1

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);
    }
}
Jakub Zalas
  • 35,761
  • 9
  • 93
  • 125
  • Ok.. that helps a lot. Thanks. If you wouldn't test with phpspec, would you go for something more top-level like behat, or just regular PHPUnit? – Adam Jun 14 '14 at 21:32
  • I'm paranoid, so i'd still try to use phpspec. It's fine if that's a single class that's responsible for disk operations, and everywhere else you mock this class. – Jakub Zalas Jun 14 '14 at 22:31
  • Yes, although my question was a bit contrived, in my actual case i have ended up extracting the FS class so i can focus on what is being written rather than if it is. Thanks – Adam Jun 15 '14 at 11:06