Search code examples
unit-testingmockingfilesystemsphpunitvfs-stream

PHP Unit testing and mocking a file system scandir()


I have a method in a class that scans a directory and creates an array of all the subdirectories. It's pretty simple and works great. However, I would like to add a unit test for this method and I am having a hard time figuring out how.

Here's my problem: I can create a virtual file system using vfsstream and it works fine. However, I can't pass that to my class to create an array from. It needs a real directory to scan. I want to test against a controlled directory (obviously so I know exactly what will the be result of every scan so I can test it). The scanned directory in production may change frequently.

So, my only solution is to create a test-specific fake directory in my test folders, pass that path to my scanner, and then check it against what I know to be in that fake directory. Is this best practice or am I missing something?

Thank you!

Here is some code: The Test

function testPopulateAuto() 
{ 
    $c = new \Director\Core\Components\Components; 

    // The structure of the file system I am checking against. This is what I want to generate. 
    $check = array( 
        'TestFolder1', 
        'TestFolder2', 
    );     

    $path = dirname( __FILE__ ) . "/test-file-system/"; // Contains TestFolder1 and TestFolder1 
    $list = $c->generateList( $path ); // Scans the path and returns an array that should be identical to $check 

    $this->assertEquals($check, $list); 
}  

Solution

  • Sorry if I misunderstood your question, but scandir should work with custom stream. Example:

    $structure = array(
            'tmp' => array(
                    'music' => array(
                            'wawfiles' => array(
                                    'mp3'                      => array(),
                                    'hello world.waw'          => 'nice song',
                                    'abc.waw'                  => 'bad song',
                                    'put that cookie down.waw' => 'best song ever',
                                    "zed's dead baby.waw"      => 'another cool song'
                            )
                    )
            )
    );
    $vfs = vfsStream::setup('root');
    vfsStream::create($structure, $vfs);
    
    $music = vfsStream::url('root/tmp/music/wawfiles');
    
    var_dump(scandir($music));
    

    Output:

    array(5) {
      [0]=>
      string(7) "abc.waw"
      [1]=>
      string(15) "hello world.waw"
      [2]=>
      string(3) "mp3"
      [3]=>
      string(24) "put that cookie down.waw"
      [4]=>
      string(19) "zed's dead baby.waw"
    }