Matthias
Matthias

Reputation: 81

How can I test a class that uses the Storage Facade?

In a Laravel 5 package I am making there is a class FileSelector that uses the Storage-facade in a certain method.

public function filterFilesOnDate($files, DateTime $date)
{
    return array_filter($files, function($file) use($date){
        return Storage::lastModified($file) < $date->getTimeStamp();
    });
}

This class takes a path (to some files) and a Storage::disk()in it's constructor.

Now I am trying to write some basic unit tests for this specific class using the Orchestra Testbench.

The setUp-function looks like this:

protected $fileSelector;
protected $date;

public function setUp()
{
    parent::setUp();
    $this->date = new DateTime();
    $this->fileSelector = new fileSelector('tests/_data/backups', Storage::disk('local'));
}

The failing test is:

public function test_if_files_are_filtered_on_date()
{
    $files = Storage::allFiles('tests/_data/backups');

    $filteredFiles = $this->fileSelector->filterFilesOnDate($files, $this->date);
}

Storage::allFiles('tests/_data/backups') returns no files at all. The path is correct because using the File-facade returns the needed files but this isn't compatible with the filterFilesOnDate()-method because it uses Storage.

Using the File-facade generates the following error:

League\Flysystem\FileNotFoundException: File not found at tests/_data/backups/ElvisPresley.zip

Am I using the Storage-methods wrong in the test or have I stumbled on a limitation of Orchestra/Testbench?

Upvotes: 2

Views: 2357

Answers (1)

Matthias
Matthias

Reputation: 81

Ok, turns out I didn't completely understand how Storageand disks worked.

Using things like Storage::lastModified() calls the default Filesystem specified in the filesystem-config.

Since this is a test there is no config.

What Storage::disk() does, is create an instance of FilesystemAdapter using a Filesystem-object So a Storage object needs to be 'recreated'.

So:

$this->fileSelector = new FileSelector('tests/_data/backups', Storage::disk('local'));

Becomes:

$this->disk = new Illuminate\Filesystem\FilesystemAdapter(
    new Filesystem(new Local($this->root))
);

$this->fileSelector = new FileSelector($this->disk, $this->path);

($this->pathis the path the where the files I use for testing are stored)

It was also pointed out to me that I should set the lastModified-timestamps manually everytime the test is run to avoid differing test results.

foreach (scandir($this->testFilesPath) as $file)
{
    touch($this->testFilesPath . '/' . $file, time() - (60 * 60 * 24 * 5));
}

Using touch you can create files or set timestamps of files. In this case, they are set to 5 days.

Upvotes: 5

Related Questions