iT邦幫忙

2022 iThome 鐵人賽

DAY 20
0
DevOps

自動化測試大作戰系列 第 20

Mocking(五):Queue

  • 分享至 

  • xImage
  •  

Medium 清新閱讀版連結

今天來看 Queue Mocking 吧!

Queue Mocking 函數

  • Queue::fake():當我們希望在執行測試目標行為時,想驗證某個 Job 類別是否有被派送至佇列中,但又不要真的觸發 Job 入列時,可在測試程式碼中呼叫此函數。
  • Queue::assertPushed():可驗證指定的 Job 類別是否被配送至佇列。需在執行 Queue::fake() 後方可使用。
  • Queue::assertPushedOn():可驗證指定的 Job 類別是否被配送至指定的佇列。需在執行 Queue::fake() 後方可使用。
  • Queue::assertNotPushed():可驗證指定的 Job 類別是否未被配送至佇列。需在執行 Queue::fake() 後方可使用。
  • Queue::assertNothingPushed():可驗證是否無 Job 類別被配送至佇列。需在執行 Queue::fake() 後方可使用。

接下來讓我們實際演練看看吧!

範例:文章瀏覽計數

  • 測試目標:文章瀏覽記錄端點

    • 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);
      });
      
  • 測試程式碼:

    <?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);
        }
    }
    

    以上測試程式碼,測試了 2 種測試案例:

    • testDispatchAddArticlePageViewJob():在這個測試案例函數中,我們驗證了當文章瀏覽記錄端點被請求,且文章存在時,有發送AddArticlePageViewJob 這個 Job 類別。
    • testNotDispatchAddArticlePageViewJob():在這個測試案例函數中,我們驗證了當文章瀏覽記錄端點被請求,且文章不存在時,沒有發送AddArticlePageViewJob 這個 Job 類別。

    以上就是今天所介紹的 Queue Mocking,大家可以多加演練。

    明天讓我們來看看Storage Mocking 與 HTTP Mocking。

    PS. 大家可以發現,Event、Mail、Queue 這三者的 Mocking方法其實都滿像的,因此將他們三者用類似的方式來介紹。

    參考資料


上一篇
Mocking(四):Mail
下一篇
Mocking(六):Storage & HTTP
系列文
自動化測試大作戰31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言