You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel测试环境模拟多Storage时遇Mockery调用异常问题

Laravel测试环境模拟多Storage组件报错问题

问题说明

在Laravel测试环境中模拟多个Storage组件时触发错误,报错发生在调用Storage::fake('public')的位置,错误提示为Mockery\Exception\BadMethodCallException: Received Mockery_2_Illuminate_Filesystem_FilesystemManager::createLocalDriver(), but no expectations were specified。

业务代码

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);
    }
}

测试用例代码

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'); // ----> 错误发生在此处
    Artisan::call('download');
}

错误信息

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

解决方案

问题根源是Storage门面被Mock接管后,再次调用Storage::fake()会触发未被Mock覆盖的方法调用:

  1. 测试开头已经通过$public_disk = Storage::fake('public');创建了public磁盘的fake实例,无需重复调用Storage::fake('public');,直接使用已创建的$public_disk即可。
  2. 当使用Storage::shouldReceive('build')给Storage设置Mock期望后,Storage门面已被Mockery代理,此时调用fake()会尝试调用createLocalDriver(),但该方法未被设置Mock期望,导致报错。

调整后的测试代码只需删除重复的Storage::fake('public');行即可:

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')
    Artisan::call('download');
}

内容的提问来源于stack exchange,提问作者Erfan Sabouri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 04:36:01