عند العمل مع تطبيقات Laravel، من الشائع مواجهة سيناريوهات حيث يحتاج الأمر إلى تنفيذ مهمة باهظة الثمن. لتجنب حظر العملية الرئيسية، قد تقرر إلغاء تحميل المهمة إلى وظيفة يمكن معالجتها بواسطة قائمة الانتظار.
دعونا نتناول مثالاً. تخيل تطبيق الأمر: يحتاج مستخدمو الاستيراد إلى قراءة ملف CSV كبير وإنشاء مستخدم لكل إدخال. إليك الشكل الذي قد يبدو عليه الأمر:
/* ImportUsersCommand.php */ namespace App\Console\Commands; /*...*/ class ImportUsersCommand extends Command { protected $signature = 'app:import-users'; public function handle() { dispatch(new ImportUsersJob()); $this->line('Users imported successfully.'); $this->line('There are: ' . User::count(). ' Users.'); } }
في هذا المثال، يرسل الأمر مهمة للتعامل مع قراءة الملف وإنشاء المستخدمين. إليك الشكل الذي قد يبدو عليه ملف ImportUsersJob.php:
/* ImportUsersJob.php */ namespace App\Jobs; /*...*/ class ImportUsersJob implements ShouldQueue { public function handle(FileReader $reader): void { foreach($reader->read('users.csv') as $data) { User::create([ 'name' => $data['name'], 'email' => $data['email'], ]); } } }
عند اختبار هذه الميزة، قد يبدو الاختبار النموذجي للأمر كما يلي:
/* ImportUsersCommandTest.php */ namespace Tests\Feature; /*...*/ class ImportUsersCommandTest extends TestCase { use RefreshDatabase; public function test_it_processes_the_file(): void { Storage::fake('local')->put('users.csv', "..."); $this->artisan('app:import-users') ->expectsOutput('Users imported successfully.') ->expectsOutput('There are: 10 Users.') ->assertSuccessful(); $this->assertDatabaseCount('users', 10); } }
للوهلة الأولى، يبدو أن هذا الاختبار يعمل بشكل مثالي. يُظهر تشغيل مجموعة الاختبار نتيجة ناجحة:
ومع ذلك، عند تشغيل الأمر app:import-users في بيئة حقيقية، قد تحصل على نتيجة غير متوقعة:
كما ترون، يشير إخراج الأمر إلى وجود 0 مستخدم في قاعدة البيانات. فلماذا يحدث هذا؟
السبب هو إرسال المهمة إلى قائمة الانتظار، لذلك لا تعمل بشكل متزامن مع تنفيذ الأمر. سيتم إنشاء المستخدمين فقط عندما تقوم قائمة الانتظار بمعالجة المهمة لاحقًا.
تستخدم مجموعة الاختبار برنامج تشغيل قائمة انتظار المزامنة بشكل افتراضي، مما يعني أنه تتم معالجة المهام بشكل متزامن أثناء الاختبار. ونتيجة لذلك، يتم تنفيذ المهمة على الفور، مما يعطي فكرة أن كل شيء يعمل كما هو متوقع.
على الرغم من أن هذا السلوك مقبول في بيئة الاختبار، فمن المهم إدراك أن نتائج العالم الحقيقي تعتمد على تكوين QUEUE_CONNECTION في بيئة الإنتاج الخاصة بك. ونظرًا لمتطلبات مشروعك، قد تعلم أنه ستتم معالجة المهمة في قائمة انتظار غير متزامنة.
بمجرد أن تدرك هذا التمييز، قد ترغب في تحسين اختباراتك لتجنب "الإيجابيات الكاذبة".
أولاً، من المهم التحقق من أن الأمر يرسل المهمة فعليًا، بغض النظر عما إذا كانت المهمة تتم معالجتها بشكل متزامن أو غير متزامن. إليك كيفية اختبار ذلك:
/* ImportUsersCommandTest.php */ namespace Tests\Feature; /*...*/ class ImportUsersCommandTest extends TestCase { public function test_it_dispatches_the_job(): void { Queue:fake(); $this->artisan('app:import-users') ->expectsOutput('Process has been queued.') ->assertSuccessful(); Queue::assertPushed(ImportUsersJob::class); } }
بمجرد التأكد من إرسال الوظيفة، يمكنك اختبار العمل الفعلي الذي تؤديه الوظيفة في اختبار منفصل. إليك كيفية تنظيم اختبار الوظيفة:
/* ImportUsersJobTest.php */ namespace Tests\Feature; /*...*/ class ImportUsersJobTest extends TestCase { use refreshDatabase; public function test_it_processes_the_file() { Storage::fake('local')->put('users.csv', "..."); app()->call([new ImportUsersJob(), 'handle']); $this->assertDatabaseCount('users', 10); } }
يضمن هذا أن الوظيفة تؤدي العمل اللازم، بغض النظر عما إذا كانت تتم معالجتها بواسطة قائمة انتظار أو بشكل متزامن.
كما هو الحال في الحياة الواقعية، قد تحدث حالات طارئة ويجب أن تكون مستعدًا لها.
سيقوم نظام قائمة الانتظار في Laravel، وفقًا لتكوين العاملين لديك، بإعادة محاولة المهام عند حدوث استثناء، وإذا تم تجاوز عمليات إعادة المحاولة، فسيتم وضع علامة على المهمة على أنها فاشلة.
إذن ماذا يحدث إذا كان الملف غير موجود؟ تحتاج إلى التعامل مع حالات الحافة هذه من خلال التحقق من صحة المدخلات ورمي الاستثناءات عند الضرورة.
إليك كيفية التعامل مع هذا الأمر في وظيفتك:
/* ImportUsersJobTest.php */ namespace App\Jobs; /*...*/ class ImportUsersJob implements ShouldQueue { use Queueable; public function handle(FileReader $reader): void { if(!Storage::disk('local')->exists('users.csv')){ throw new Exception('The users.csv file doesn\'t exist.') } foreach($reader->read('users.csv') as $data) { User::create([ 'name' => $data['name'], 'email' => $data['email'], ]); } } }
إليك كيفية اختبار هذا السيناريو:
/* ImportUsersJobTest.php */ namespace Tests\Feature; /*...*/ class ImportUsersJobTest extends TestCase { use refreshDatabase; /*...*/ public function test_it_fails_when_file_doesnt_exist(): void { Storage::fake('local'); $this->expectException(Exception::class); $this->expectExceptionMessage('The users.csv file doesn\'t exist.'); dispatch(new ImportUsersJob()); } }
يضمن هذا النهج أن تعكس اختباراتك بشكل أكثر دقة كيفية معالجة الوظائف في العالم الحقيقي.
يمكن تطبيق نفس الإستراتيجية عندما ترسل وحدة التحكم مهمة إلى قائمة انتظار أو حيث يتم وضع مستمع الأحداث في قائمة الانتظار.
كما هو الحال دائمًا، قم بتعديل هذه الممارسات لتناسب مشروعك وفريقك.
يسعدني أن أسمع أفكارك!
تنصل: جميع الموارد المقدمة هي جزئيًا من الإنترنت. إذا كان هناك أي انتهاك لحقوق الطبع والنشر الخاصة بك أو الحقوق والمصالح الأخرى، فيرجى توضيح الأسباب التفصيلية وتقديم دليل على حقوق الطبع والنشر أو الحقوق والمصالح ثم إرسالها إلى البريد الإلكتروني: [email protected]. سوف نتعامل مع الأمر لك في أقرب وقت ممكن.
Copyright© 2022 湘ICP备2022001581号-3