laravel バッチコマンドをテストする

## 概要

- バッチコマンドをテストするFeatureテストのコードを記載してみる。

## 前提

- 下記のようなバッチコマンドが定義されているとする。（hogeテーブルのlimit_atの値がバッチ実行時間より過去ならそのレコードを削除する）

    ```app/Console/Commands/CleanupExpiredHogeCommand.php
    <?php
    
    declare(strict_types=1);
    
    namespace App\Console\Commands;
    
    use Illuminate\Console\Command;
    use App\Models\Hoge as HogeModel;
    use Carbon\CarbonImmutable;
    
    class CleanupExpiredHogeCommand extends Command
    {
        /**
         * The name and signature of the console command.
         *
         * @var string
         */
        protected $signature = 'app:cleanup-expired-hoge-command';
    
        /**
         * The console command description.
         *
         * @var string
         */
        protected $description = 'hogeテーブルの有効期限切れのレコードを削除';
    
        /**
         * Execute the console command.
         */
        public function handle(): void
        {
            $this->info('hogeテーブルの有効期限切れのレコードの削除処理開始');
        
            $this->cleanup();
        
            $this->info('hogeテーブルの有効期限切れのレコードの削除処理終了');
        }
    
        /**
         * 有効期限切れのレコードを削除する
         *
         * @return void
         */
        public function cleanup(): void
        {
            $HogeModel = new HogeModel();
            $now = CarbonImmutable::now();
            $HogeModel->where('limit_at', '<', $now)->delete();
        }
    }
    ```

- テストコードを記載するFeatureテストのクラスは下記のようなTestCaseクラスを継承しているものとする。

    ```TestCase.php
    <?php
    
    declare(strict_types=1);
    
    namespace Tests\Base\Feature;
    
    use Illuminate\Foundation\Testing\DatabaseMigrations;
    use Illuminate\Support\Facades\Mail;
    use Illuminate\Testing\TestResponse;
    use Tests\TestCase as BaseTestCase;
    
    class TestCase extends BaseTestCase
    {
        use DatabaseMigrations;
    
        public function setUp(): void
        {
            parent::setUp();
        
            // シーダーの実行
            $this->seed();
        
            Mail::fake();
        }
    }

    ```

## 方法

- Artisanファサードのcallメソッドを使いバッチコマンドを呼び出してテストする。下記にコードを記載する。

    ```CleanupExpiredHogeCommandTest.php
    <?php
    
    declare(strict_types=1);
    
    namespace Tests\Feature;
    
    use Tests\Base\Feature\TestCase;
    use App\Models\Hoge as HogeModel;
    use Carbon\CarbonImmutable;
    use Illuminate\Support\Facades\Artisan;
    
    /**
     * make class-test class=tests/Feature/App/Console/Commands/CleanupExpiredHogeCommandTest.php
     */
    class CleanupExpiredHogeCommandTest extends TestCase
    {
        /**
         * 正常系
         *
         * make class-test class=tests/Feature/App/Console/Commands/CleanupExpiredHogeCommandTest.php method=test_期限切れのレコードを削除する
         *
         * @return void
         */
        public function test_期限切れのレコードを削除する(): void
        {
            // NOTE: subMinuteは引数を指定しないと1分減算する
            $limitAt = CarbonImmutable::now()->subMinute();
            // 1分だけ期限切れになっているレコードの作成
            HogeModel::factory()->createOne([
                'limit_at' => $limitAt,
            ]);
        
            $exitCode = Artisan::call('app:cleanup-expired-hoge-command');
        
            // バッチの正常終了を確認
            $this->assertEquals(0, $exitCode);
            // テーブルにレコードが無いことを確認
            $this->assertDatabaseCount('hoge', 0);
        }
    }
    ```