In testing the Aura.Http package, I have realized that it's much more flexible, testing wise, to pass around file resources (a.k.a. handles, pointers, or streams) than it is to pass around file names. When you do that, you can use a php://memory stream instead of attempting to touch the file system. For example:

<?php
// $this->save('/path/to/file.txt', 'Hello World!');
public function save($file, $data)
{
    file_put_contents($file, $data);
}

The test would have to be something like this

<?php
public function testSave()
{
    $file = '/path/to/file.txt';
    $data = 'Hello World!';
    $this->system_under_test->save($file, $data);
    $this->assertTrue(file_exists($file));
    $actual = file_get_contents($file);
    $this->assertSame($data, $actual);
    unlink($file);
}

All sorts of things can go wrong with that, starting with file permissions. It's also against testing dogma, in that you touch the file system.

However, if you rewrite the method to use a file resource instead of a file name ...

<?php
// $fp = fopen('/path/to/file.txt', 'w+');
// $this->save($fp, 'Hello World!');
public function save($resource, $data)
{
    fwrite($resource, $data);
}

This places control of the file creation in your hands directly, not under the control of the system under test. Then the test looks like this (with a helper method):

<?php
protected function readResource($resource)
{
    rewind($resource);
    $data = null;
    while (! feof($resource)) {
        $data .= fread($resource, 8192);
    }
    return $data;
}

public function testSave()
{
    $fp = fopen('php://memory');
    $data = 'Hello World!';
    $this->system_under_test->save($fp, $data);

    $actual = $this->readResource($fp)
    $this->assertSame($data, $actual);
}

Voila! No more touching the file system.


Are you stuck with a legacy PHP application? You should buy my book because it gives you a step-by-step guide to improving you codebase, all while keeping it running the whole time.