LoginSignup
0
0

More than 1 year has passed since last update.

Laravel用パッケージでArtisanコマンドを書く場合のテスト

Posted at

発生事象

Laravel用のパッケージを書いていて、コマンドを追加したのでテストしてみるぞ~、と思ったら、以下のようなエラーメッセージが出た。

sampleTest.php
//テストはだいたいこんな感じ
class SampleTest extends \Orchestra\Testbench\TestCase {
    public function test_command(){
        $this->artisan('nice:easy')->assertExitCode(10);
    }
}
Symfony\Component\Console\Exception\CommandNotFoundException: The command "nice:easy" does not exist.

コマンドを認識していないようだ。

結論

ココを見ましょう。
https://orchestraplatform.readme.io/docs/testbench#section-custom-service-providers
https://orchestraplatform.readme.io/docs/testbench

To load your package service provider, override the getPackageProviders()

おまえのパッケージのサービスプロバイダをロードするには、getPackageProviders() をオーバーライドせい、ということで、解決。

補足

コマンド登録はパッケージのサービスプロバイダに書く

Artisanコマンドを提供するようなLaravel用パッケージを作成する場合、パッケージ側にサービスプロバイダを用意して、「この辺のクラスをArtisanコマンドに追加せよ」という情報を、利用側のLaravel本体に知らせる必要があります。

=>このへんの話
https://laravel.com/docs/8.x/packages#commands
https://readouble.com/laravel/8.x/ja/packages.html#commands

パッケージ開発のテストには orchestral/testbench を使う

Laravel用パッケージを開発する場合、Testには
https://github.com/orchestral/testbench
を使いましょう。

=>このへんの話
https://readouble.com/laravel/8.x/ja/packages.html#a-note-on-facades

FeatureTestですよ、という話

そもそもの話として、Artisanコマンド(Illuminate\Console\Command を継承したクラス)に対してUnitTestを書こうとすると、色々と面倒なことになる(何が面倒なのか書くのもめんどい)。

Artisanコマンドを書く場合は、責任の範囲を画面との入出力のみに限定し、それ以外の処理に関しては適切に移譲するように注意しする。

端的には、Illuminate\Console\Command を継承して作成するクラスは、ViewとControllerに相当するもの、と扱っておけばよい。(なので、Artisanコマンドに対するテストは、UnitTestでははなくFeatureTestです。)

Commandのコンストラクタをオーバライドするなよ、という話

ちなみに、Illuminate\Console\Command を継承してクラスを作成する場合は コンストラクタをオーバーライドしてはいけない

理由はこちら https://qiita.com/k-kurikuri/items/cec750ec3d21c6319253

移譲先のオブジェクト生成は、handle()メソッドの先頭で行うようにしておくのが良いと思う。

SampleCommand.php
class TemplateList extends Command
{
    /** @var string $signature */
    protected $signature = 'big-na-otoko:do-it';
    /** @var string $description */
    protected $description = '将来なにかデカイことをやるコマンドです';
    /** @var NiceService $service */
    private $service;

    /**
     * @return void
     */
    public function handle()
    {
        try {
            $this->init();
        } catch (\Throwable $e) {
            $this->error($e->getMessage());
            return 1;
        }
        //以下に、入出力に関する処理とサービスの呼び出しなどを書いて適宜実装していく
    }

    /**
     * @return void
     */
    private function init(): void
    {
        $this->service = App::make(NiceService ::class);
    }
}

こんなノリで書いておけば、だいたい問題なくテストできるはず。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0