تخطَّ إلى المحتوى

لماذا تستغرق مجموعة اختباراتك إحدى عشرة دقيقة

المجموعة البطيئة مجموعة يتخطاها الناس. والوقت لا يكاد يكون في التأكيدات: بل في إعادة بناء قاعدة البيانات، وتجزئة كلمات المرور، والخروج إلى الشبكة دون قصد.

قراءة 3 دقيقة

المجموعة التي تستغرق إحدى عشرة دقيقة لا تُشغَّل قبل الدفع. يشغّلها التكامل المستمر، بعد أن يكون السياق قد ضاع، فيتحول تصحيح من خمس ثوانٍ إلى رحلة ذهاب وإياب من عشرين دقيقة. وفي النهاية يدفع أحدهم فوق بناء أحمر لأنه واثق إلى حد ما أنه لا علاقة له.

فسرعة المجموعة إذن ليست راحة للمطوّر. بل هي ما يقرر هل تؤدي الاختبارات عملها.

قِس قبل أن تخمّن

php artisan test --profile

يطبع هذا أبطأ الاختبارات. وتكاد تستحوذ حفنة حالات دائمًا على أغلب زمن الساعة، ويكون الإصلاح محددًا لا معماريًا.

قاعدة البيانات، وهي أغلبه عادةً

الهجرة عند كل اختبار. الـ trait المسمى RefreshDatabase يلف كل اختبار في معاملة ويعكسها، وهذا سريع. أما DatabaseMigrations فيشغّل كل هجرة لكل اختبار، وهذا ليس كذلك. وفي مشروع فيه مئتا هجرة، ذلك الفارق هو المشكلة كلها.

هجرات بدل تفريغ مخطط. حتى مرة واحدة لكل جولة، إعادة تشغيل مئتي هجرة تستغرق أطول من تحميل نتيجتها:

php artisan schema:dump --prune

فتحمّل المجموعة عندئذٍ ملف SQL واحدًا. وهذا أكبر مكسب منفرد في شيفرة ناضجة ويكلّف أمرًا واحدًا.

مصانع تنشئ أكثر مما يحتاجه الاختبار. مصنع بسلسلة has() ينشئ عشرين سجلًا مرتبطًا لاختبار يقرأ حقلًا واحدًا. أنشئ الحد الأدنى، واستخدم make() بدل create() حيث لا شيء يلمس قاعدة البيانات.

تجزئة كلمات المرور، وهي ما لا يتوقعه أحد

التجزئة بطيئة عمدًا - ذلك غرضها. والمجموعة التي تنشئ مئات المستخدمين عبر مصنع تدفع تلك الكلفة مئات المرات.

// tests/TestCase.php أو Pest.php
Hash::driver('bcrypt')->setRounds(4);

في المجموعات كثيرة التجهيزات المستخدمة، خفّض هذا وحده أزمنة التشغيل إلى النصف.

اختبارات تخرج إلى الشبكة

الفئة الأشد ضررًا، لأنها بطيئة وغير موثوقة في آن. الاختبار الذي يستدعي واجهة حقيقية ينتظر خادم شخص آخر ويفشل حين يكون لذلك الخادم يوم سيئ.

Http::preventStrayRequests();

ضع ذلك في حالة الاختبار الأساسية. فأي اختبار يجري استدعاء HTTP غير مُحاكى يفشل فورًا ويخبرك أيّه - وستجد بعضها لم تكن تعلم بوجودها.

وينطبق الأمر نفسه على الطوابير والبريد والتخزين. محاكاةً تكون فورية؛ وحقيقيةً تؤدي عملًا لا يؤكّد عليه الاختبار.

الانتظار والاستطلاع

الأمر sleep(2) في اختبار ينتظر شيئًا غير متزامن ثانيتان في كل جولة، إلى الأبد، وهو إما طويل أكثر من اللازم وإما - على جهاز أبطأ - غير كافٍ.

مساعدات الوقت في Laravel تجعل الانتظار غير ضروري: جمّد الوقت، وسافر إلى الأمام، وأكّد. وللعمل غير المتزامن فعلًا، شغّل الطابور تزامنيًا في الاختبارات بدل انتظار عامل.

اختبارات المتصفح، وهي في سلة أخرى

هي بطيئة لأنها تقود متصفحًا حقيقيًا، ولا حيلة تجعل ذلك سريعًا. والجواب الكمّ لا السرعة: عدد صغير يغطي المسارات المهمة، يُشغَّل منفصلًا عن المجموعة السريعة، كي لا يقف بين مطوّر وتغذيته الراجعة.

التوازي، متى استحقته الاختبارات

php artisan test --parallel

تحسّن شبه خطي على جهاز متعدد النوى - وسيكشف كل اختبار كان يعتمد بهدوء على آخر. ملفات تجهيزات مشتركة، ومعرّفات مرمَّزة، وسجل يُفترض وجوده لأن اختبارًا سابقًا أنشأه.

تلك الإخفاقات تستحق أن تحدث. الاختبار الذي لا ينجح إلا إذا شُغِّل بعد آخر ليس اختبارًا بل تسلسلًا، وكان سيفشل عشوائيًا في التكامل المستمر على أي حال.

الهدف

تحت الدقيقة للمجموعة التي يشغّلها الناس قبل الدفع، وكل ما هو أبطأ - اختبارات المتصفح، والتكامل مقابل خدمات حقيقية - في مهمة منفصلة تعمل بعدها.

والمقياس ليس التغطية ولا الأناقة. بل هل تشغيل الاختبارات شيء يفعله مطوّر دون أن يقرره.

المجموعة التي لا يشغّلها أحد هي أيضًا مجموعة لا يستطيع أحد أن يرقّي خلفها. ولهذا فبناؤها هو المرحلة الأولى من الترقية لا الأخيرة. وإن كانت المجموعة السريعة تعمل على SQLite بينما يعمل الإنتاج على MySQL، فلتلك المقايضة كلفة، وليست صغيرة دائمًا.

أسئلة ذات صلة

ما السرعة التي ينبغي أن تكون عليها المجموعة؟
سريعة بما يكفي ألا يكون تشغيلها قرارًا. تحت الدقيقة يشغّلها الناس قبل كل دفع بلا تفكير؛ وبعد الخمس يبدؤون بالدفع وانتظار التكامل المستمر، ما ينقل التغذية الراجعة من ثوانٍ إلى دقائق ويكلّف أكثر بكثير من الوقت الموفَّر.
هل قاعدة بيانات في الذاكرة هي الجواب؟
سريعة، وهي قاعدة بيانات مختلفة عن التي تشغّلها في الإنتاج، ما يعني أنها لن تلتقط مخالفة القيد ولا مشكلة الترتيب ولا الهجرة التي تقفل. معقولة لمجموعة تغلب عليها اختبارات الوحدة؛ وخطرة كشيء وحيد بينك وبين خطأ في المخطط.
هل يساعد التشغيل المتوازي؟
كثيرًا، وفقط متى كانت الاختبارات معزولة بما يكفي للنجاة منه. كل ما يكتب في مسار تجهيزات مشترك أو معرّف سجل ثابت أو خدمة خارجية سيفشل متقطعًا تحت التوازي - وذلك يستحق الإصلاح على أي حال، لأنها الاختبارات نفسها التي تفشل عشوائيًا في التكامل المستمر.
أين ننظر أولًا؟
إلى أبطأ عشرة اختبارات، لا إلى المتوسط. عادةً تهيمن على المجموعات حفنة حالات تفعل شيئًا غاليًا، وإصلاحها أمسية واحدة. أما إعادة كتابة المجموعة كلها من أجل السرعة فلا.

← العودة إلى كل المقالات

اتصل بنا+1 848 272 7583واتساب+90 850 308 5436البريدinfo@codefacture.comصفحة التواصل