Laravelでコマンドライン処理の単体テストを行う

# 目次
Laravelの記事一覧は下記
[PHPフレームワークLaravelの使い方](https://qiita.com/toontoon/items/c4d0371e504c37f6576e)

# Laravelバージョン
動作確認はLaravel Framework 7.19.1で行っています

# 前提条件
[eclipseでLaravel開発環境を構築する。デバッグでブレークポイントをつけて止める。(WindowsもVagrantもdockerも)](https://qiita.com/toontoon/items/76fa7f8845b20776077c)
本記事は上記が完了している前提で書かれています
プロジェクトの作成もapacheの設定も上記で行っています

[Laravelでコマンドライン処理を行う](https://qiita.com/toontoon/items/2015ec0deea4b11e5361)
[Laravelのタスクスケジューラを使う](https://qiita.com/toontoon/items/777c427345780411da8b)
本記事は上記が完了している前提で書かれています
上記記事で作成したクラスを使っていきます


# テストクラス作成
(1) [Laravelでコマンドライン処理を行う](https://qiita.com/toontoon/items/2015ec0deea4b11e5361)
上記記事で作成したSampleCommand.phpのテストクラスを作成します
/sample/tests/Feature/SampleCommandTest.php作成

```SampleCommandTest.php
<?php

namespace Tests\Feature;

use PHPUnit\Framework\TestResult;
use Tests\TestCase;

class SampleCommandTest extends TestCase
{
    public function testHandle()
    {

        $arg1 = 'aaa';
        $arg2 = 'bbb';
        $arg3 = 'ccc';
        $option1 = true;
        $option2 = 'eee';
        $option3 = 'fff';
        $option4 = ['ggg', 'hhh'];

        $console = $this->artisan('sample:name1 aaa bbb ccc --option1 --option2=eee --option3=fff --option4=ggg --option4=hhh');

        $console->expectsOutput('下記入力を受け付けました');
        $console->expectsOutput('arg1:' . $arg1);
        $console->expectsOutput('arg2:' . $arg2);
        $console->expectsOutput('arg3:' . $arg3);
        $console->expectsOutput('option1:' . $option1);
        $console->expectsOutput('option2:' . $option2);
        $console->expectsOutput('option3:' . $option3);
        $console->expectsOutput('option4:' . var_export($option4, true));

        $in = 'aaa';
        $console->expectsQuestion('何か入力してください', $in);
        $console->expectsOutput('下記入力を受け付けました');
        $console->expectsOutput($in);

        $in = 'bbb';
        $console->expectsQuestion('何か入力してください。この入力中はユーザーがタイプした値を表示しません', $in);
        $console->expectsOutput('下記入力を受け付けました');
        $console->expectsOutput($in);

        $console->expectsQuestion('yかyesを入力するとtrueとして扱います', 'yes');
        $console->expectsOutput('true');

        $in = ['Laravel', 'apache'];
        $console->expectsQuestion('選択入力。カンマ区切りで複数入力できます', $in);
        $console->expectsOutput('下記入力を受け付けました');
        $console->expectsOutput(var_export($in, true));

        $console->expectsOutput('テーブル出力');
        $console->expectsOutput('+--------+--------+--------+--------+');
        $console->expectsOutput('| col1   | col2   | col3   | col4   |');
        $console->expectsOutput('+--------+--------+--------+--------+');
        $console->expectsOutput('| 1-col1 | 1-col2 | 1-col3 | 1-col4 |');
        $console->expectsOutput('| 2-col1 | 2-col2 | 2-col3 | 2-col4 |');
        $console->expectsOutput('| 3-col1 | 3-col2 | 3-col3 | 3-col4 |');
        $console->expectsOutput('+--------+--------+--------+--------+');

        $console->expectsOutput('プログレスバー出力');

        $console->expectsOutput('');
        $console->expectsOutput('エラー出力');

        $console->assertExitCode(0);

    }

}
```

`$this->artisan`に渡している引数はコマンド処理を実行するときにphp artisanに渡している引数そのままです(SampleCommandクラスの$signature変数に定義した通り)
その他の部分について[Laravelでコマンドライン処理を行う](https://qiita.com/toontoon/items/2015ec0deea4b11e5361)で作成したSampleCommand.phpと見比べてみましょう
lineメソッド、tableメソッド、errorメソッドがexpectsOutputになり
askメソッド、secretメソッド、confirmメソッド、choiceメソッドがexpectsQuestionになっていることはわかるでしょう
expectsOutputメソッドでコンソールに出力される値のテスト
expectsQuestionメソッドでユーザー入力のテスト
assertExitCodeメソッドで戻り値のテスト
ができます


(2) [Laravelのタスクスケジューラを使う](https://qiita.com/toontoon/items/777c427345780411da8b)
上記記事で作成したSampleSchedule.phpのテストクラスを作成します
/sample/tests/Feature/SampleScheduleTest.php作成

```SampleScheduleTest.php
<?php

namespace Tests\Feature;

use PHPUnit\Framework\TestResult;
use Tests\TestCase;

class SampleScheduleTest extends TestCase
{
    public function testHandle()
    {

        $arg1 = 'a';
        $console = $this->artisan('sample:name2 ' . $arg1);
        $console->expectsOutput('arg1:' . $arg1);
        $console->assertExitCode(1);

        $arg1 = 'z';
        $console = $this->artisan('sample:name2 ' . $arg1);
        $console->expectsOutput('arg1:' . $arg1);
        $console->assertExitCode(0);

    }

}
```

# 動作確認
コマンドラインで
`cd sample`
`.\vendor\bin\phpunit tests/Feature/SampleCommandTest.php`
(windowsでない場合./vendor/bin/phpunit)

実行結果

```
PHPUnit 8.5.2 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 10.44 seconds, Memory: 22.00 MB

OK (1 test, 31 assertions)
```


コマンドラインで
`.\vendor\bin\phpunit tests/Feature/SampleScheduleTest.php`
(windowsでない場合./vendor/bin/phpunit)

実行結果

```
PHPUnit 8.5.2 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 416 ms, Memory: 20.00 MB

OK (1 test, 4 assertions)
```