環境
- Laravel Framework 6.0.3
- Mockery 1.0
- Docker 19.03.4 (Laravelの実行環境)
背景
Laravelではファサードをモックしたテストを手軽に書く事ができます。公式ドキュメントにもある通り、モックされたファサードはMockery
インスタンスを返します。そのため、Mockery::with
でファサードの引数を検証する事ができます。
課題
ファサードの引数にランダムな値が含まれる場合などにwith
で正規表現を使いたい場合、直感的に正規表現を書いても認識されません。
例
以下のようなファイルをアップロードするコマンドがあるとします。同名のファイルが存在する場合は、上書きしないように元の名前にユニークな値を追記したファイル名でアップロードします。
コマンド
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
class FileUploadCommand extends Command
{
protected $signature = 'uploadfile';
public function handle()
{
$filename = 'uploadfile.txt';
$content = 'これからアップロードされるファイルです';
if (! Storage::disk('backups')->exists($filename)) {
Storage::disk('backups')->put($filename, $content);
Log::info('新規ファイルがアップロードされました。ファイル名:' . $filename);
} else {
$rename = sprintf('%s.%s', $filename, Str::uuid());
Log::info('既に同名のファイルが存在したためリネームしました。ファイル名:' . $rename);
}
}
}
テスト
with
に正規表現っぽい値を入れて、リネーム処理のテストを書いてみます。
<?php
namespace Tests\Feature;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Mockery;
use Tests\TestCase;
class FileUploadCommandTest extends TestCase
{
public function testリネーム処理()
{
Storage::disk('backups')->put(
'uploadfile.txt',
'これはアップロード済みファイルです'
);
Log::shouldReceive('info')->once()->with("/既に同名のファイルが存在したためリネームしました。ファイル名:/");
$this->artisan('uploadfile');
}
}
テスト実行
[root@1b8af3a695ec www]# vendor/bin/phpunit tests/Feature/FileUploadCommandTest.php
PHPUnit 8.3.5 by Sebastian Bergmann and contributors.
E 1 / 1 (100%)
Time: 1.11 seconds, Memory: 24.00 MB
There was 1 error:
1) Tests\Feature\FileUploadCommandTest::testリネーム処理()
Mockery\Exception\NoMatchingExpectationException: No matching handler found for Mockery_0_Illuminate_Log_LogManager::info('既に同名のファイルが存在したためリネームしました。ファイル名:uploadfile.txt.c91c2c81-f26a-4c02-8dda-5e9c260af597'). Either the method was unexpected or its arguments matched no expected argument list for this method
実行しても正規表現としては、見なされないようでテストは失敗します^^;
解決方法
Mockery::patternを使います。
テストコードを修正
正規表現っぽく書いた場所をMockery::pattern
を使って書き直してみます。
- Log::shouldReceive('info')->once()->with("/既に同名のファイルが存在したためリネームしました。ファイル名:/");
+ Log::shouldReceive('info')->once()->with(Mockery::pattern("/既に同名のファイルが存在したためリネームしました。ファイル名:/"));
テスト再実行
[root@1b8af3a695ec www]# vendor/bin/phpunit tests/Feature/FileUploadCommandTest.php
PHPUnit 8.3.5 by Sebastian Bergmann and contributors.
. 1 / 1 (100%)
Time: 1.76 seconds, Memory: 24.00 MB
OK (1 test, 2 assertions)
🎉