0

Suppose I have the following class:

class FooBar
{
    public function getArrayFromFile($file)
    {
        if (!is_readable($file)) {
            return [];
        }

        return include $file;
    }
}

Assuming $file contains the following:

return [
...
];

How does one test it? Specifically how do you create a double for "include".

1 Answers1

1

You can do it a couple of ways.

You can create a test file that contains some contents and use that file in your test. This is probably the easiest but it means that in order for your tests to work you need to have this file located in the suite.

To keep from having to keep track of test files you can mock the file system. The PHPUnit documentation recommends using vfsStream. This way you can create a fake file and using that in your method. This will also make it easier to set permissions so that you can test the is_readable condition.

http://phpunit.de/manual/current/en/phpunit-book.html#test-doubles.mocking-the-filesystem

So in PHPUnit your test would look like this:

public function testGetArrayFromFile() {
    $root = vfsStream::setup();
    $expectedContent = ['foo' => 'bar'];
    $file = vfsStream::newFile('test')->withContent($expectedContent);
    $root->addChild($file);

    $foo = new FooBar();
    $result = $foo->getArrayFromFile('vfs://test');

    $this->assertEquals($expectedContent, $result);
}

public function testUnreadableFile() {
    $root = vfsStream::setup();

    //2nd parameter sets permission on the file.
    $file = vfsStream::newFile('test', 0000); 
    $root->addChild($file);

    $foo = new FooBar();
    $result = $foo->getArrayFromFile('vfs://test');

    $this->assertEquals([], $result);
}
Schleis
  • 41,516
  • 7
  • 68
  • 87
  • Thanks mate, I'll try this tomorrow. I was under the impression that you may not use a stream for "include". – Stoked PHP Engineer Jul 30 '14 at 16:20
  • My main problem is creating a double for "include", native PHP functions like is_readable can be doubled easily. – Stoked PHP Engineer Jul 30 '14 at 16:23
  • The main idea being not too try to create a double of the that function. How the contents of the file are return is not totally important just that the they are returned. You want to test what your code is doing, not how it does it. – Schleis Jul 30 '14 at 16:25
  • @Schleis I think testing this function is a little pointless as it will always return and it will be array, if based on the file, which I assume it is going to be dynamic and as such I think it should be excluded from tests. – DaGhostman Dimitrov Jul 30 '14 at 16:28
  • @DaGhostmanDimitrov Given a file return the contents or an empty array as necessary. That isn't pointless, the test is simple. You are also now prepared for modifying the functionality if you want to enforce that an array is always returned. – Schleis Jul 30 '14 at 17:42
  • // You want to test what your code is doing, not how it does it. // @Schleis, that I am fully aware of, it's just that this is very convenient and straightforward. I believe the question then becomes... in this example is TDD telling me that this implementation is bad? Are there other compelling reason to not go this route aside from it being untestable? – Stoked PHP Engineer Aug 10 '14 at 12:13
  • This route isn't untestable. It is just tricky with the fact that you need to deal with the file system. So you either need a file in your test suite to use or you need some way to point PHP at a "fake" filesystem that you can make provide the files. – Schleis Aug 11 '14 at 13:09