30 Days of Automated Testing:Using PHPUnit【D20】

Mocking (Part 5): Queue

WilliamP
3 min readFeb 9, 2023

Let’s look at Queue Mocking today!

Queue Mocking Functions

  • Queue::fake(): When we want to verify that a Job class has been dispatched to the queue during the execution of the target behavior but do not actually trigger the Job enqueueing, we can call this function in the test code.
  • Queue::assertPushed(): Verifies if the specified Job class has been dispatched to the queue. This can only be used after Queue::fake() has been executed.
  • Queue::assertPushedOn(): Verifies if the specified Job class has been dispatched to the specified queue. This can only be used after Queue::fake() has been executed.
  • Queue::assertNotPushed(): Verifies if the specified Job class has not been dispatched to the queue. This can only be used after Queue::fake() has been executed.
  • Queue::assertNothingPushed(): Verifies if no Job class has been dispatched to the queue. This can only be used after Queue::fake() has been executed.

Next, let’s practice and see it in action!

Example:Article View Counting

Test Target:Article view counting endpoint

  • database/migrations/2022_10_02_174939_create_articles_table.php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('articles', function (Blueprint $table) {
$table->id();
$table->text('content');
$table->integer('page_views');
$table->timestamps();
});
}

/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('articles');
}
};
  • app/Models/Article.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
use HasFactory;

protected $fillable = [
'content',
'page_views',
];
}
  • database/factories/ArticleFactory.php
<?php

namespace Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;

/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Article>
*/
class ArticleFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition()
{
return [
'content' => $this->faker->text,
'page_views' => 0,
];
}
}
  • app/Jobs/AddArticlePageViewJob.php
<?php

namespace App\Jobs;

use App\Models\Article;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;

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

private $article;

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

/**
* Execute the job.
*
* @return void
*/
public function handle()
{
$this->article->page_views += 1;
$this->article->save();
}
}
  • routes\api.php
<?php

use App\Jobs\AddArticlePageViewJob;
use App\Models\Article;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

Route::post('/article/{id}/page-view', function (Request $request, $id) {
$article = Article::find($id);

if (empty($article)) {
return response()->json([], 404);
}

AddArticlePageViewJob::dispatch($article)->onQueue('redis');

return response('', 200);
});

Test Code:

<?php

namespace Tests\Feature;

use App\Jobs\AddArticlePageViewJob;
use App\Models\Article;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Queue;
use Tests\TestCase;

class QueueTest extends TestCase
{
use RefreshDatabase;

public function testDispatchAddArticlePageViewJob()
{
$article = Article::factory()->create();

Queue::fake();

$response = $this->post(route('add-article-page-views', ['id' => $article->id]));
$response->assertOk();

Queue::assertPushedOn('redis', AddArticlePageViewJob::class);
}

public function testNotDispatchAddArticlePageViewJob()
{
$article = Article::factory()->create();

Queue::fake();

$response = $this->post(route('add-article-page-views', ['id' => $article->id . '0']));
$response->assertNotFound();

Queue::assertNotPushed(AddArticlePageViewJob::class);
}
}

The above test code tests two test cases:

  • testDispatchAddArticlePageViewJob(): In this test case function, we verify that when the article view history endpoint is requested and the article exists, the AddArticlePageViewJob job class is dispatched.
  • testNotDispatchAddArticlePageViewJob(): In this test case function, we verify that when the article view history endpoint is requested and the article does not exist, the AddArticlePageViewJob job class is not dispatched.

The above is an introduction to Queue Mocking today. You can practice more.

Next, let’s take a look at Storage Mocking and HTTP Mocking.

If you liked this article or found it helpful, feel free to give it some claps and follow the author!

Reference

Articles of This Series

--

--