«هل يمكن تشغيل ملف واحد فقط مع الاختبارات؟» — نعم، وإليك كيفية القيام بذلك في Go
\n\nهل سبق لك أن جلست أمام الطرفية، وكتبت go test ./... وشاهدت برعب كيف تبدأ قاعدة الشيفرة الكاملة لمشروعك في Go بتشغيل مئات الاختبارات؟ بينما كنت تحتاج فقط للتحقق من ملف صغير واحد يحتوي على حالات الاختبار التي كتبتها للتو. مألوف؟ إذا كان الأمر كذلك، فقد أتيت إلى المكان الصحيح.
في هذه المقالة، سنحلل سؤالاً شائعاً من Stack Overflow (بالمناسبة، لديه آلاف المشاهدات): «How to run test cases in a specified file?». سنقوم بتكييف الإجابات مع واقع مطور Go ونعرض ليس فقط الأوامر الأساسية، ولكن أيضاً الحيل التي ستوفر لك ساعات من العمل. هيا بنا!
\n\nلماذا لا يكون go test البسيط مناسباً دائماً؟
\n\nفي المشاريع الكبيرة، تنقسم الاختبارات إلى اختبارات وحدات، واختبارات تكامل، واختبارات شاملة. إذا قمت بتشغيل go test ./...، فإن Go يجتاز جميع الحزم الفرعية بشكل متكرر وينفذ جميع الاختبارات التي يجدها. قد يستغرق هذا دقائق. وإذا كان لديك اختبارات تصل إلى قاعدة بيانات أو واجهات برمجة تطبيقات خارجية، فقد تفشل لأسباب خارجة عن إرادتك. لذلك، فإن القدرة على تشغيل حالات الاختبار في ملف محدد ليست مجرد راحة، بل هي مهارة مطور محترف.
الأمر الأساسي: go test مع اسم الملف
\n\nالطريقة الأكثر مباشرة هي تحديد ملف معين مع الاختبارات. ولكن هناك فارق بسيط: Go يتطلب منك تحديد كل من الملف الذي يتم اختباره والملف الذي يحتوي على الاختبارات معاً. لماذا؟ لأن المترجم يجب أن يجمع كل شيفرة الحزمة.
\n\nلنفترض أن لديك هيكل المشروع التالي:
\n\nmyproject/\n├── main.go\n└── math_utils.go\n└── math_utils_test.go\n\n\nلتشغيل الاختبارات فقط من math_utils_test.go، نفذ:
go test -v math_utils.go math_utils_test.go\n\n\nالعلم -v (verbose) سيعرض معلومات مفصلة عن كل حالة اختبار. بدونه، سترى النتيجة النهائية فقط: PASS أو FAIL.
مثال على شيفرة حقيقية
\n\nلننشئ ملفاً بسيطاً math_utils.go:
package main\n\nfunc Sum(a, b int) int {\n return a + b\n}\n\nfunc Multiply(a, b int) int {\n return a * b\n}\n\n\nوملف الاختبار math_utils_test.go:
package main\n\nimport "testing"\n\nfunc TestSum(t *testing.T) {\n result := Sum(2, 3)\n if result != 5 {\n t.Errorf("Sum(2, 3) = %d; want 5", result)\n }\n}\n\nfunc TestMultiply(t *testing.T) {\n result := Multiply(3, 4)\n if result != 12 {\n t.Errorf("Multiply(3, 4) = %d; want 12", result)\n }\n}\n\n\nالآن نشغل:
\n\n$ go test -v math_utils.go math_utils_test.go\n=== RUN TestSum\n--- PASS: TestSum (0.00s)\n=== RUN TestMultiply\n--- PASS: TestMultiply (0.00s)\nPASS\nok command-line-arguments 0.002s\n\n\nلاحظ المخرجات: ok command-line-arguments. هذا يعني أن Go قام بتجميع حزمة مؤقتة من الملفات المحددة. هذا الأسلوب يعمل، ولكن له قيود.
مشكلة مع عدة ملفات في نفس الحزمة
\n\nإذا كانت حزمتك تتكون من عدة ملفات (على سبيل المثال، math_utils.go و strings_utils.go)، وكان الاختبار في math_utils_test.go يستدعي دالة من strings_utils.go، فإن الأمر أعلاه سيفشل مع خطأ في التجميع. سيشتكي Go من أن الدالة غير معرفة.
الحل هو سرد جميع الملفات التابعة. لكن هذا غير مريح. من الأفضل استخدام نهج آخر.
\n\nالطريقة المتقدمة: تصفية الاختبارات حسب الاسم (-run)
\n\nالعلم -run يسمح لك بتشغيل حالات الاختبار التي تتطابق أسماؤها مع تعبير منتظم فقط. هذا ليس مرتبطاً بالملف، ولكن إذا قمت بتسمية الاختبارات بشكل هادف، فمن السهل تصفية ما تحتاجه.
مثال: تشغيل جميع الاختبارات التي تبدأ بـ TestSum:
go test -v -run T