
Serpent Team

Andrew Hanna

علشان تشغّل اختبارات Apex بالتوازي من غير فشل عشوائي (flaky)، خلّي كل اختبار ينشئ بياناته بنفسه، وما تكتبش أبدًا في سجلات موجودة خارج الاختبار، وولّد قيم فريدة للحقول زي أسماء المستخدمين. وبعدها شخّص أي فشل عشوائي متبقي بإعادة تشغيل الكلاس ده لوحده: لو نجح لوحده وفشل بالتوازي، يبقى عندك مشكلة عزل مش bug. أما إيقاف التشغيل المتوازي على مستوى الـ org كلها فبيخبّي العَرَض وبيبطّأ كل تشغيل.
افتراضيًا، Salesforce بتشغّل كلاسات الاختبار غير المتزامنة في نفس الوقت، فممكن اختبارين يتنافسوا على نفس المورد في نفس اللحظة. والفشل بيرجع لثلاثة أسباب رئيسية:
UNABLE_TO_LOCK_ROW، والحد ده مش قابل
للتغيير، زي ما
بتشرح Xappex. السجلات الأب بتتقفل في صمت عند تحديث سجلات الأبناء في علاقة master-detail، وعند
إعادة حساب roll-up summaries، وأثناء معالجة المشاركة (sharing).
[email protected] في نفس الوقت
هيفشلوا بخطأ DUPLICATE_USERNAME، وده نمط
بيوثّقه Salesforce Central.
@isTest(SeeAllData=true) بيقرا ويكتب في سجلات حقيقية ممكن اختبارات
تانية تلمسها في نفس الوقت.
ولا واحدة من دي بتظهر لما الكلاس يشتغل لوحده، وعلشان كده الـ suite بتبان كأنها بتفشل عشوائيًا.
UNABLE_TO_LOCK_ROW وDUPLICATE_USERNAME
وأي أخطاء قيم مكررة على بيانات الاختبار بتشاور على مشكلة تزامن.
--synchronous في Salesforce
CLI بيشغّل methods الاختبار في كلاس Apex واحد بشكل متزامن، بحسب
توثيق plugin-apex.
@TestSetup أو data factory واستغنَ عن SeeAllData=true.
الاختبارات اللي بتبني بياناتها بنفسها ما بتتنافسش على سجلات الـ org.
@isTest(isParallel=true) لتمييز الكلاسات اللي تقدر تشتغل بالتوازي من
غير حدود التزامن الافتراضية، زي ما
بيوضح FishOfPrey. ضيفه بس للكلاسات
اللي بتنجح بشكل متكرر في التشغيل المتوازي.
كحل مؤقت بس. الإعداد موجود في Setup ثم Apex Test Execution ثم Options، وبيشغّل الاختبارات غير المتزامنة واحد ورا التاني. ده بيشيل فشل التزامن، لكن في الـ orgs اللي فيها كلاسات اختبار كتير التشغيل الكامل ممكن ياخد وقت أطول بكتير. وفيه أدوات بتعتمد على نفس الإعداد: توثيق Gearset بيذكر إن test monitors عندها بتستخدم Tooling API وبالتالي بتشغّل الاختبارات بالتوازي إلا لو فعّلت الإعداد ده.
اعتبر الخانة دي علامة على دَين تقني. فعّلها علشان تعدّي release، وبعدين صلّح الكلاسات المسببة للمشكلة ورجّعها مقفولة.
sf apex run test --test-level RunLocalTests بيديك نفس التشغيل المتوازي
اللي هتشوفه عمليات النشر على الإنتاج.
--result-format junit --output-dir علشان الـ pipeline تتابع الفشل لكل
كلاس على مدار الوقت، و--code-coverage علشان التغطية تفضل واضحة.
إعادة المحاولة العمياء مغرية، لكنها بتحوّل العيوب الحقيقية لـ builds خضرا. ونفس الانضباط ده مطلوب لما تغيّر أدواتك، زي ما شرحنا في كيف تغيّر أداة Salesforce DevOps من غير ما تكسر الـ pipeline ودليلنا عن الانتقال من Gearset إلى Serpent من غير توقف.
الإصدارات اللي بتتم بالنقر بتقابل نفس الأخطاء، لأن الاختبارات بتشتغل برضه وقت النشر. قائمة التحقق للنشر بالنقر بتوضح تراجع إيه الأول، وتقدر تتصفح أدلة عملية أكتر في SF Guides.
Tekunda هي شركة الاستشارات والمنتجات على Salesforce اللي بتبني Serpent، منصة Salesforce DevOps فيها إدارة إصدارات عبر GitHub وpipelines نشر مؤتمتة. لو الاختبارات العشوائية معطّلة إصداراتك، قارن الخطط في صفحة الأسعار.
هل تشغّل Salesforce اختبارات Apex بالتوازي افتراضيًا؟
نعم، التشغيل غير المتزامن بينفّذ الكلاسات في نفس الوقت، إلا لو كان Disable Parallel Apex Testing مفعّل في Setup.
ما سبب UNABLE_TO_LOCK_ROW في اختبارات Apex؟
معاملتين عايزين نفس السجل، وغالبًا بيكون سجل أب مقفول بسبب تحديث master-detail أو roll-up summary أو إعادة حساب المشاركة. المعاملة المستنية بتفشل بعد 10 ثواني.
هل أعيد تشغيل اختبارات Apex العشوائية تلقائيًا؟
مرة واحدة، بشكل متزامن، ولأخطاء التزامن بس. سجّل كل حالة وصلّح الكلاس بدل ما تعتمد على إعادة المحاولة.
هل يكفي isParallel=true لحل الاختبارات العشوائية؟
لا. هو بس بيعلّم الكلاس إنه آمن للتشغيل المتوازي. الاختبار لسه لازم ينشئ بياناته بنفسه ويستخدم قيم فريدة.
بدون التزام.