Skip to main content

Command Palette

Search for a command to run...

Eventlar va Event Job larni Laravelda testlash

Published
5 min read
Eventlar va Event Job larni Laravelda testlash

Ilovangiz uchun testlar yozish — bu kodingiz kutilganidek ishlashini ta’minlashning muhim qismi. Ammo, Laravel’da hodisalar va hodisa vazifalarini test qilish haqida gap ketganda, ishlar biroz qiyinlashishi mumkin. Ushbu blogda biz Laravel’da hodisalar va hodisa vazifalarini qanday test qilishni o‘rganamiz.

Birinchidan, Laravel’da hodisalar va hodisa vazifalari nima ekanligini tushunib olaylik.

Laravel’ning hodisalari oddiy obunachi-obzervatorni amalga oshirishni ta’minlaydi, bu bizga ilovangizda sodir bo‘ladigan turli hodisalarga obuna bo‘lish va ularni kuzatish imkonini beradi. Laravel standart bo‘yicha bir qancha hodisalarni taqdim etadi, masalan, model hodisalari va autentifikatsiya hodisalari, lekin siz ilovangizning ehtiyojlariga mos ravishda maxsus hodisalar ham yaratishingiz mumkin.

Hodisa vazifalari asosiy tarmoqni bloklamasdan fon rejimida biror vazifani bajarish usulidir. Ushbu vazifalar navbatga qo‘yilishi va asinxron tarzda qayta ishlanishi mumkin, bu sizning ilovangizga vazifa fon rejimida ishlayotgan paytda so‘rovlarni qayta ishlashni davom ettirish imkonini beradi. Laravel’da hodisa vazifalari odatda elektron pochta jo‘natish, hisobotlar yaratish yoki ma’lumotlarni qayta ishlash kabi bajarilishi uzoq vaqt talab qiladigan murakkab vazifalarni bajarish uchun ishlatiladi.

Endi hodisalar va hodisa vazifalarining nima ekanligini tushunganligimizdan so‘ng, ularni test qilishga kirishamiz.

Hodisani test qilish

Faraz qilaylik, bizning mijozlar jadvalimizda mijozlar ro‘yxati mavjud va biz mijozlar bilan uchrashuv belgilashimiz va ma’lumotlarni uchrashuvlar jadvalimizga saqlashimiz kerak. Bizda uchrashuvlarga tegishli barcha narsalarni boshqarish uchun tizimimizda quyidagi model sinfi Meeting mavjud.

class Meeting extends Model {
    protected $fillable = [
        'meeting_date',
        'meeting_time',
        'email_to',
        'mail_content',
        'status',
        'created_by',
    ];

    protected $dates = [
        'meeting_date',
    ];

    public function creator(): BelongsTo
    {
        return $this->belongsTo(User::class, 'created_by', 'id');
    }

    protected static function boot()
    {
        parent::boot();

        static::creating(function ($model) {
            $model->created_by = auth()->id();
        });
    }
}

Bizda uchrashuv ma’lumotlarini saqlash uchun MeetingController sinfi va quyidagi marshrut mavjud.

use App\Controller;

class MeetingController extends Controller {

    public function store(MeetingRequest $request) {
        try { 
            $meeting  = Meeting::create($request->validated());

            MeetingCreated::dispatch($meeting);
        } catch(\Exception $exception){
            Log::error($exception->getMessage());

            return response()->json($meeting);
        }   

        return response()->json($meeting, 201);
    }
}
Route::post('/meetings', [MeetingController::class, 'store'])->name('meetings.create');

Faraz qilaylik, mijoz bilan belgilangan uchrashuv haqida elektron pochta xabarini yuboradigan MeetingCreated hodisamiz mavjud.

<?php

namespace App\Providers;

use App\Events\MeetingCreated;
use App\Listeners\SendMeetingEmail;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;

class EventServiceProvider extends ServiceProvider
{
    protected $listen = [
        MeetingCreated::class => [
            SendMeetingEmail::class,
        ],
    ];
}

Laravel’da hodisalarni test qilishda birinchi qadam hodisani ishga tushiradigan test yaratishdir. Masalan, meetings.store marshrut uchun kontroller amalini test qilishimiz mumkin, bu o‘z navbatida MeetingCreated hodisasini ishga tushiradi.

namespace Tests\Feature;

use Tests\TestCase;
use App\Models\User;
use Illuminate\Support\Facades\Event;

class LeadMailControllerTest extends TestCase
{
    use RefreshDatabase;

    public function setUp(): void
    {
        parent::setUp();
        $this->actingAs(User::factory()->create());
    }

    /**
    * foydalanuvchi uchrashuv yaratishi mumkin
    *
    * @test
    */
    public function test_user_can_create_a_meeting()
    {
        Event::fake();

        $attributes = Meeting::factory()->make();
        $response   = $this->post(route('meetings.store', $attributes));

        $response->assertCreated();
        $this->assertDatabaseHas('meetings', $attributes);
        Event::assertDispatched(MeetingCreated::class);
    }
}

Ushbu testda biz Event::fake() usulidan foydalanib, hodisa jo‘natuvchisini soxtalashtiramiz, shuning uchun hodisa jo‘natilmaydi. Keyin meetings.store marshrutiga uchrashuv ma’lumotlarini jo‘natib, yangi uchrashuv yaratamiz, bu MeetingCreated hodisasini ishga tushiradi. Nihoyat, biz Event::assertDispatched() usulidan hodisaning jo‘natilganligini tasdiqlash uchun foydalanamiz.

Yuqoridagi test muvaffaqiyatli o‘tadi, ammo agar biz uchrashuvni yaratgan foydalanuvchi yaratuvchi sifatida belgilanganligini tekshirish uchun yuqoridagi kodga yangi tasdiqlash qo‘shsak, bu test muvaffaqiyatsiz bo‘ladi, chunki biz barcha hodisalarni soxtalashtirayapmiz.

namespace Tests\Feature;

use Tests\TestCase;
use App\Models\User;
use Illuminate\Support\Facades\Event;

class LeadMailControllerTest extends TestCase
{
    use RefreshDatabase;

    public function setUp(): void
    {
        parent::setUp();
        $this->actingAs(User::factory()->create());
    }

    /**
    * foydalanuvchi uchrashuv yaratishi mumkin
    *
    * @test
    */
    public function test_user_can_create_a_meeting()
    {
        Event::fake();

        $attributes = Meeting::factory()->make();
        $response   = $this->post(route('meetings.store', $attributes));

        $response->assertCreated();
        $this->assertDatabaseHas('meetings', $attributes);
        Event::assertDispatched(MeetingCreated::class);

        // yaratuvchi belgilanganligini tekshirish
        $latestMeeting = Meeting::latest()->first();
        $this->assertEquals(auth()->id(), $latestMeeting->created_by);
    }
}

Ushbu muammoni hal qilish uchun faqat MeetingCreated hodisasini soxtalashtirishimiz kerak, quyida ko‘rsatilganidek.

public function test_user_can_create_a_meeting()
{
    Event::fake([
        MeetingCreated::class,
    ]);

    $attributes = Meeting::factory()->make();
    $response   = $this->post(route('meetings.store', $attributes));

    $response->assertCreated();
    $this->assertDatabaseHas('meetings', $attributes);
    Event::assertDispatched(MeetingCreated::class);

    // yaratuvchi belgilanganligini tekshirish
    $latestMeeting = Meeting::latest()->first();
    $this->assertEquals(auth()->id(), $latestMeeting->created_by);
}

Hodisa vazifasini va tinglovchini test qilish

Hodisa vazifalarini test qilishda avvalo, vazifani navbatga qo‘yuvchi testni yaratishimiz kerak. Masalan, keling, mijozga uchrashuv haqida elektron pochta xabarini jo‘natuvchi SendMeetingEmail hodisa vazifamiz bor deb faraz qilaylik. Mana shu hodisa vazifasi uchun misol test:

/**
* @test
*/
public function test_send_meeting_email_job()
{
    Queue::fake();

    $meeting = Meeting::factory()->create();
    MeetingCreated::dispatch($meeting);

    Queue::assertPushed(CallQueuedListener::class, function ($job) {
        return $job->class == SendMeetingEmail::class;
    });
}

Ushbu testda biz Queue::fake() usulidan foydalanib, navbatni soxtalashtiramiz, shuning uchun vazifa bajarilmaydi. Keyin zavod yordamida yangi uchrashuv yaratamiz, bu SendMeetingEmail vazifasini navbatga qo‘yishi kerak. Nihoyat, biz Queue::assertPushed() usulidan vazifaning navbatga qo‘yilganligini tasdiqlash uchun foydalanamiz.

Hodisa vazifasini bajarilishini test qilish

Biz vazifaning navbatga qo‘yilganligini tasdiqlaganimizdan so‘ng, vazifaning to‘g‘ribajarilganligini test qilishimiz mumkin. Mana SendMeetingEmail hodisa vazifasi va unga mos test uchun misol.

namespace App\Listeners;

use App\Constants\Queue;
use App\Events\MeetingCreated;
use Illuminate\Contracts\Queue\ShouldQueue;

/**
 * Class SendMeetingEmail
 */
class SendMeetingEmail implements ShouldQueue
{
    /**
     * @var string $queue
     */
    public string $queue = Queue::EMAIL;

    /**
     * Hodisani boshqarish.
     *
     * @param MeetingCreated $event
     *
     * @return void
     */
    public function handle(MeetingCreated $event)
    {
        $meeting    = $event->meeting;

        Mail::to($meeting->email_to)
            ->queue((new MeetingEmail($meeting))
            ->onQueue(Queue::EMAIL));
    }
}
<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

/**
 * Class MeetingEmail
 *
 * @package App\Notifications
 */
class MeetingEmail extends Mailable implements ShouldQueue
{
    use Queueable;
    use SerializesModels;

    /**
     * @var Meeting|null
     */
    public array $meeting;

    /**
     * Yangi xabar instance-ni yaratish.
     *
     * @return void
     */
    public function __construct(Meeting $meeting)
    {
        $this->meeting = $meeting;
    }

    /**
     * Xabarni yaratish.
     *
     * @return $this
     */
    public function build(): MeetingEmail
    {
        $mailable    = $this->from($this->meeting->creator->email, $this->meeting->creator->name);
        $mailable    = $mailable->subject("Uchrashuv tasdiqlandi");
        $mailable    = $mailable->text('email.meeting.index', ['meeting' => $this->meeting]);

        return $mailable;
    }
}
public function test_send_meeting_email_job_execution()
{
    Mail::fake();

    $meeting = Meeting::factory()->create();
    $event    = new MeetingCreated($leadMail);
    event($event);

    Mail::assertQueued(MeetingEmail::class, 
        function ($mail) use ($meeting) {
            return $mail->hasTo($meeting->email_to) &&
                   $mail->hasFrom($meeting->creator->email) &&
                   $mail->hasSubject('Uchrashuv tasdiqlandi'); 
        }
    );
}

Ushbu testda biz Mail::fake() usulidan foydalanib, pochta jo‘natuvchini soxtalashtiramiz, shuning uchun elektron pochta jo‘natilmaydi. Keyin zavod yordamida yangi foydalanuvchini yaratamiz va MeetingCreated hodisasining yangi nusxasini yaratamiz va uni event() usuli yordamida jo‘natamiz. Keyin biz elektron pochta jo‘natilishi uchun navbatga qo‘yilganligini va elektron pochtaning turli xususiyatlarini, masalan, hasTo, hasFrom, hasSubject va boshqalarni tasdiqlashimiz mumkin.

Xulosa

Laravel’ning hodisa tizimi bizning ilovamizda hodisalarga obuna bo‘lish va o‘zgarishlarni kuzatishning samarali usulini ta’minlaydi. Hodisa vazifalari ilovangizga murakkab vazifalarni fon rejimida bajarayotgan paytda so‘rovlarni qayta ishlashni davom ettirish imkonini beradi. Ammo, testni qachon va qanday boshlashni bilmaganda, odatda bu qiyinchilik tug‘diradi.

Hodisalarni test qilishda Event::fake() usulidan foydalanib, hodisa jo‘natuvchisini soxtalashtirish va hodisaning jo‘natilmasligini ta’minlash muhimdir. Ammo, ilovangizning boshqa qismlariga xalaqit bermaslik uchun faqat test qilish kerak bo‘lgan hodisalarni soxtalashtirish kerakligini unutmang.

More from this blog

Rashidov Nuriddin

34 posts