kiyon's avatar
Level 11

How can I test a failed job

Hello everyone, I have a Job.

<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use App\User;

class StatJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public $user;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct(User $user)
    {
        $this->user = $user;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        \Log::info('begin the job handle.');
        throw_if($this->user->id == 2, \Exception::class, 'some error message');
    }
}

And a service provider which have registered into config/app.php.

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Queue\Events\JobProcessed;
use Illuminate\Queue\Events\JobFailed;

class QueueServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot()
    {
        // listen to job processed and failed events
        \Queue::after(function (JobProcessed $event) {
            \Log::info('Job was done.');
            $payload = unserialize($event->job->payload()['data']['command']);
            $this->countStatJob($payload);
        });
        \Queue::failing(function (JobFailed $event) {
            \Log::info('Job was failed.');
            $payload = unserialize($event->job->payload()['data']['command']);
            $this->countStatJob($payload);
        });
    }

    /**
     * Register the application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    private function countStatJob($payload)
    {
        $user = $payload->user;
        \Log::info('user info in the payload:' . $user->toJson());

        $count = \Cache::store('file')->increment('statistical');
        if ($count >= 50) {
            \Log::info('send notification to administrator');
        }
    }
}

Phpunit environment like this.

<php>
    <env name="APP_ENV" value="testing"/>
    <env name="DB_CONNECTION" value="sqlite"/>
    <env name="DB_DATABASE" value=":memory:"/>
    <env name="CACHE_DRIVER" value="array"/>
    <env name="SESSION_DRIVER" value="array"/>
    <env name="QUEUE_DRIVER" value="sync"/>
</php>

Here is my test file.

<?php

namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
use App\User;
use App\Jobs\StatJob;

class StatTest extends TestCase
{
    use RefreshDatabase;

    /**
     * @test
     */
    public function it_knows_if_the_job_is_done()
    {
        $users = create(User::class, 2);

        \Cache::store('file')->set('statistical', 48, 1);

        StatJob::dispatch($users[0]);

        $completedCount = \Cache::store('file')->get('statistical');
        $this->assertEquals(49, $completedCount);

        $this->expectException(\Exception::class);
        StatJob::dispatch($users[1]);

        // the rest case cannot be tested
        dd('interact');
        $completedCount = Cache::store('file')->get('statistical');

        $this->assertEquals(50, $completedCount);
    }
}

After running the test, I have logs below.

[2018-01-15 01:15:50] testing.INFO: begin the job handle.  
[2018-01-15 01:15:50] testing.INFO: Job was done.  
[2018-01-15 01:15:50] testing.INFO: user info in the payload{"id":1,"name":"Dixie Corkery","avatar_path":"http:\/\/localhost\/images\/avatars\/default.png","confirmed":true,"confirmation_token":null,"created_at":"2018-01-15 01:15:50","updated_at":"2018-01-15 01:15:50"}  
[2018-01-15 01:15:50] testing.INFO: begin the job handle.  
[2018-01-15 01:15:50] testing.INFO: Job was failed.  
[2018-01-15 01:15:50] testing.INFO: user info in the payload{"id":2,"name":"Jettie Upton","avatar_path":"http:\/\/localhost\/images\/avatars\/default.png","confirmed":true,"confirmation_token":null,"created_at":"2018-01-15 01:15:50","updated_at":"2018-01-15 01:15:50"}  
[2018-01-15 01:15:50] testing.INFO: send notification to administrator  

My question is how can I test the job failed event?

0 likes
4 replies
franciscocaldeira's avatar

@kiyon I think you have the test on wrong order:

/**
* @test
*/
public function it_knows_if_the_job_is_done()
{
    $users = create(User::class, 2);

    \Cache::store('file')->set('statistical', 48, 1);

    StatJob::dispatch($users[0]);

    $completedCount = \Cache::store('file')->get('statistical');
    $this->assertEquals(49, $completedCount);

    //If you do dispatch first, then assert later, don't forget your user id must be 2, the rest must be tested with ok.
    StatJob::dispatch($users[1]); 
    $this->expectException(\Exception::class);
    
    // the rest case cannot be tested
    dd('interact');
    $completedCount = Cache::store('file')->get('statistical');

    $this->assertEquals(50, $completedCount);
}

Please or to participate in this conversation.