Laravel 5.2 で、EC2インスタンスの起動・停止等を行う Web 管理画面を
作成しています。
本番インスタンスを使ってアプリのテストをするのは(AWSの)APIやCPUの
無駄遣いなので、DBと遅延ジョブを使ったシミュレーションクラスを実装
しました。
画面上で[実行中]インスタンスの[停止]ボタンを押すと、表示上は[停止中]
になり、内部的には Job キューを登録して、数十秒後には[停止]に変わる
ような動きです。
アプリとしては概ね問題なく動いていますが、テストコードでつまずいて
います。以下、質問のために、簡略化したコードを書きました。
artisan でコマンド(RunCommand)を発行すると、内部的に dispatch()
でジョブ(BatchJob)を発行します。ログを確認すると、普通にコマンドを
実行した場合は以下のようになります:
bash
1$ tail -f storage/logs/laravel.log 2[2016-10-25 15:13:53] local.INFO: App\Console\Commands\RunCommand::handle() called. 3[2016-10-25 15:13:53] local.INFO: App\Jobs\BatchJob::__construct() called. 4sqlite> select * from jobs; 52|default|{"job":"Illuminate\\Queue\\CallQueuedHandler@call","data":{"commandName":"App\\Jobs\\BatchJob","command":"O:17:\"App\\Jobs\\BatchJob\":4:{s:10:\"connection\";N;s:5:\"queue\";N;s:5:\"delay\";i:600;s:6:\"\u0000*\u0000job\";N;}"}}|0|0||1477376633|1477376033
このケースでは BatchJob::handle() は呼ばれず、その代わりジョブがDB に
キューイングされます。その後、artisan queue:work 等を流すと状態遷移が
起こります。
これが想定する動作なのですが、これを phpunit 経由で実行すると、なぜか
handle() まで即時に通ってしまい、ジョブがキューイングされず、想定した
動きになりません。
bash
1$ tail -f storage/logs/laravel.log 2[2016-10-25 15:12:59] testing.INFO: App\Console\Commands\RunCommand::handle() called. 3[2016-10-25 15:12:59] testing.INFO: App\Jobs\BatchJob::__construct() called. 4[2016-10-25 15:12:59] testing.INFO: App\Jobs\BatchJob::handle() called.
もし回避できる書き方がありましたら、方法をご教示いただければ幸いです。
(artisanコマンド)
PHP:app/Console/Commands.RunCommand.php
1<?php 2 3namespace App\Console\Commands; 4 5use Illuminate\Console\Command; 6use App\Jobs\BatchJob; 7use Illuminate\Foundation\Bus\DispatchesJobs; 8 9class RunCommand extends Command 10{ 11 use DispatchesJobs; 12 13 protected $signature = 'runcommand:run'; 14 protected $description = 'Command description'; 15 16 public function __construct() 17 { 18 parent::__construct(); 19 } 20 21 public function handle() 22 { 23 $msg = __METHOD__.'() called.'; 24 $this->info($msg); 25 \Log::info($msg); 26 $job = (new BatchJob())->delay(60*10); 27 $this->dispatch($job); // ジョブの投入 28 } 29}
(キュー投入部分)
PHP:app/Jobs/BatchJob.php
1<?php 2 3namespace App\Jobs; 4 5use App\Jobs\Job; 6use Illuminate\Queue\SerializesModels; 7use Illuminate\Queue\InteractsWithQueue; 8use Illuminate\Contracts\Queue\ShouldQueue; 9 10class BatchJob extends Job implements ShouldQueue 11{ 12 use InteractsWithQueue, SerializesModels; 13 14 public function __construct() 15 { 16 \Log::info(__METHOD__.'() called.'); 17 } 18 19 public function handle() 20 { 21 \Log::info(__METHOD__.'() called.');// 実際にはここで状態遷移を行う 22 } 23}
(テストコード)
<?php use Illuminate\Foundation\Testing\WithoutMiddleware; use Illuminate\Foundation\Testing\DatabaseMigrations; use Illuminate\Foundation\Testing\DatabaseTransactions; use App\Console\Commands\RunCommand; use Symfony\Component\Console\Application; use Symfony\Component\Console\Tester\CommandTester; class BatchJobTest extends TestCase { public function setUp() { parent::setUp(); $test = new RunCommand; // 起動対象クラス $test->setLaravel($this->app); $app = new Application(); $app->add($test); // ApplicationにCommandを登録 $command = $app->find('runcommand:run'); $this->command = new CommandTester($command); // CommandTesterを被せる } /** * artisan コマンドラッパー * パラメーターの詳細は CommandTester::execute() を参照 * * @return string */ protected function execute(array $input = [], $options = []) { $this->command->execute($input, $options); return $this->command->getDisplay(); } public function testRunCommandThenJobWillBeQueued() { $this->execute(); } } ~
【実際のテストコード】
PHP
1 $this->visit('/') // ここにアクセスして 2 ->press('停止') // これを押したら 3 ->seePageIs('/') // ここに戻って 4 ->see('停止処理中') // これが表示されて、、くれない 5 ->dontSee($one_hour_after) 6 ->see('手動モードへ');
「停止」を押すと、状態を「動作中」から「停止処理中」にして、ジョブキューに
『30秒後に状態を「停止済み」に変更する』ための処理を登録しています。
ところが PHPUnit 経由だと、即時に状態が「停止処理中」→「停止済み」に変わって
しまい、テストに失敗します。
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/10/25 08:14