Test multi storage in laravel

57 views Asked by At

I have a issue while trying to mock multi Storage in laravel test enviromnment.

Here is my my code:

public function sftp ( Sibling $sibling ) {
        $file_paths = Storage::build($sibling->config)
                             ->files($this->track->track_token);
        Storage::disk('public')
               ->makeDirectory($this->track->track_token);
        foreach ( $file_paths as $file_path ) {
            $file_content = Storage::build($sibling->config)
                                   ->get($file_path);
            TrackMp3::query()
                    ->where('track_id' , $this->track->id)
                    ->where('file_name' , basename($file_path))
                    ->update([
                                 'downloaded_at' => now() ,
                             ]);
            Storage::disk('public')
                   ->put($file_path , $file_content);
        }
    }

Here is my test case:



public function test_sftp_works_when_track_exists_in_sibling () {
        $track_token = md5('sample');
        $track_320 = UploadedFile::fake()
                                 ->create('track_320.mp3')
                                 ->getContent();
        $track_160 = UploadedFile::fake()
                                 ->create('track_160.mp3')
                                 ->getContent();
        $track_96 = UploadedFile::fake()
                                ->create('track_96.mp3')
                                ->getContent();
        $track_demo = UploadedFile::fake()
                                  ->create('track_demo.mp3')
                                  ->getContent();
        $sibling = SiblingFactory::new()
                                 ->create();
        $public_disk = Storage::fake('public');
        $sibling_disk = Storage::fake('sibling');
        Storage::shouldReceive('build')
               ->with($sibling->config)
               ->andReturn($sibling_disk);
        $sibling_disk->put($track_token . '/track_320.mp3' , $track_320);
        $sibling_disk->put($track_token . '/track_160.mp3' , $track_160);
        $sibling_disk->put($track_token . '/track_96.mp3' , $track_96);
        $sibling_disk->put($track_token . '/track_demo.mp3' , $track_demo);
        $track = TrackFactory::new()
                             ->md5Fetched()
                             ->has(TrackMp3Factory::new([ 'md5' => md5_file($sibling_disk->path($track_token . '/track_320.mp3')) ])
                                                  ->fileName320())
                             ->has(TrackMp3Factory::new([ 'md5' => md5_file($sibling_disk->path($track_token . '/track_160.mp3')) ])
                                                  ->fileName160())
                             ->has(TrackMp3Factory::new([ 'md5' => md5_file($sibling_disk->path($track_token . '/track_96.mp3')) ])
                                                  ->fileName96())
                             ->has(TrackMp3Factory::new([ 'md5' => md5_file($sibling_disk->path($track_token . '/track_demo.mp3')) ])
                                                  ->fileNameDemo())
                             ->create([ 'track_token' => $track_token ]);

        Storage::fake('public'); // ----> Error happend here
        Artisan::call('download');
    }

Here is the error:

Mockery\Exception\BadMethodCallException: Received Mockery_2_Illuminate_Filesystem_FilesystemManager::createLocalDriver(), but no expectations were specified
C:\Development\projects\track-download-manager\vendor\laravel\framework\src\Illuminate\Support\Facades\Facade.php:353
C:\Development\projects\track-download-manager\vendor\laravel\framework\src\Illuminate\Support\Facades\Storage.php:107
C:\Development\projects\track-download-manager\tests\Feature\DownloadCommandTest.php:55
2

There are 2 answers

1
Jeyhun Rashidov On BEST ANSWER

you've called Storage::fake() more than once. first for sibling and then for public. When you call it the second time, Laravel is attempting to create a local disk and because you've mocked the Storage facade earlier, the test breaks.

The key is to set up your fakes before you set up any mocks.

$public_disk = Storage::fake('public');
$sibling_disk = Storage::fake('sibling');

Storage::shouldReceive('build')
    ->with($sibling->config)
    ->andReturn($sibling_disk);

If you're not checking the interaction with Storage::build in this test and only need to make sure that files are correctly placed on the sibling and public disks, consider removing the shouldReceive('build') mocking.

If you still face issues, you can reset the mocked instance after you're done with it to ensure no side effects for subsequent calls.

Storage::swap($this->app['files']);
0
Erfan Sabouri On

Finally solve it.

I forgot to mock public disk.

    public function test_sftp_works_when_track_exists_in_sibling () {
            $track_token = md5(rand());
            $track_320 = UploadedFile::fake()
                                     ->create('track_320.mp3')
                                     ->getContent();
            $track_160 = UploadedFile::fake()
                                     ->create('track_160.mp3')
                                     ->getContent();
            $track_96 = UploadedFile::fake()
                                    ->create('track_96.mp3')
                                    ->getContent();
            $track_demo = UploadedFile::fake()
                                      ->create('track_demo.mp3')
                                      ->getContent();
            $sibling = SiblingFactory::new()
                                     ->create();
            $public_disk = Storage::fake('public');
            $sibling_disk = Storage::fake('sibling');
            Storage::shouldReceive('build')
                   ->with($sibling->config)
                   ->andReturn($sibling_disk);
            Storage::shouldReceive('disk')
                   ->with('public')
                   ->andReturn($public_disk);
            $sibling_disk->put($track_token . '/track_320.mp3' , $track_320);
            $sibling_disk->put($track_token . '/track_160.mp3' , $track_160);
            $sibling_disk->put($track_token . '/track_96.mp3' , $track_96);
            $sibling_disk->put($track_token . '/track_demo.mp3' , $track_demo);
            $track = TrackFactory::new()
                                 ->md5Fetched()
                                 ->has(TrackMp3Factory::new([ 'md5' => md5_file($sibling_disk->path($track_token . '/track_320.mp3')) ])
                                                      ->fileName320())
                                 ->has(TrackMp3Factory::new([ 'md5' => md5_file($sibling_disk->path($track_token . '/track_160.mp3')) ])
                                                      ->fileName160())
                                 ->has(TrackMp3Factory::new([ 'md5' => md5_file($sibling_disk->path($track_token . '/track_96.mp3')) ])
                                                      ->fileName96())
                                 ->has(TrackMp3Factory::new([ 'md5' => md5_file($sibling_disk->path($track_token . '/track_demo.mp3')) ])
                                                      ->fileNameDemo())
                                 ->create([ 'track_token' => $track_token ]);
    
            Artisan::call('download');
        }