質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
PHPUnit

PHPUnitは、PHP向けのユニット・テスト向けフレームワークで、手動では手間のかかるテスト作業を自動化し、繰り返し実行することが可能です。

Laravel 5

Laravel 5は、PHPフレームワークLaravelの最新バージョンで、2014年11月に発表予定です。ディレクトリ構造がが現行版より大幅に変更されるほか、メソッドインジェクションやFormRequestの利用が可能になります。

Q&A

解決済

1回答

5276閲覧

Laravel : PHPUnit経由だとJobがキューイングされない

hotta

総合スコア1613

PHPUnit

PHPUnitは、PHP向けのユニット・テスト向けフレームワークで、手動では手間のかかるテスト作業を自動化し、繰り返し実行することが可能です。

Laravel 5

Laravel 5は、PHPフレームワークLaravelの最新バージョンで、2014年11月に発表予定です。ディレクトリ構造がが現行版より大幅に変更されるほか、メソッドインジェクションやFormRequestの利用が可能になります。

0グッド

1クリップ

投稿2016/10/25 07:10

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 経由だと、即時に状態が「停止処理中」→「停止済み」に変わって
しまい、テストに失敗します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

Queueのドライバは、普段はdatabaseを使われているという認識でよろしいでしょうか。
(.envのQUEUE_DRIVER値)

Laravelのphpunitでは、初期状態だとQueueのドライバを同期処理のsyncで上書きします。
手元で試せてなくて恐縮ですが、Laravelのプロジェクトルートにある
phpunit.xmlファイルの末尾の方に、QUEUE_DRIVERを上書きしている箇所があるので

<env name="QUEUE_DRIVER" value="sync"/>

ここをdatabaseにするなり、行自体を削除して実行するとどうでしょうか。

投稿2016/10/25 08:11

Archsted

総合スコア452

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hotta

2016/10/25 08:14

ビンゴでした! database に変えたらキューイングされるようになりました。 感謝です。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問