كيفية قياس تغطية الاختبارات في Go دون أن تصاب بالجنون
\n\nلقد كتبت اختبارات لتطبيق Go الخاص بك. هل تشعر وكأنك بطل خارق؟ هذا صحيح. ولكن هناك فارق بسيط: ما مقدار الكود الذي تغطيه الاختبارات بالضبط؟ بدون إجابة على هذا السؤال، ثقتك ليست سوى تخمين.
\n\nسؤال "How to measure test coverage in Go" هو أحد أكثر الأسئلة شيوعًا على Stack Overflow (عشرات الآلاف من المشاهدات). وهذا ليس من قبيل الصدفة. المطورون لا يريدون فقط كتابة الاختبارات، بل فهم مدى فعاليتها. في هذا الدليل التعليمي، سنشرح جميع طرق قياس تغطية الاختبارات في Go: من الأوامر الأساسية إلى التقنيات المتقدمة مع ملفات التعريف وتقارير HTML.
\n\nما هي تغطية الاختبارات ولماذا يجب قياسها؟
\n\nTest coverage (تغطية الكود بالاختبارات) هي مقياس يوضح النسبة المئوية من الكود المصدري الخاص بك التي يتم تنفيذها أثناء الاختبارات. يتم التعبير عنها كنسبة مئوية. 100% coverage ليست دائمًا الكأس المقدسة، ولكن السعي لتحقيق نسب عالية يستحق العناء.
\n\nلماذا هذا ضروري؟
\n- \n
- مراقبة الجودة: ترى أي أجزاء من الكود بقيت بدون اختبارات \n
- الثقة في إعادة الهيكلة: التغطية العالية تقلل من خطر كسر شيء ما \n
- مقاييس CI/CD: يمكنك تعيين حد للتغطية ومنع الكود ذي التغطية المنخفضة \n
- التوثيق: الاختبارات هي توثيق حي، والتغطية تظهر مدى اكتمالها \n
المفاجأة: التغطية ≠ جودة الاختبارات
\nتذكر: 100% coverage لا يضمن عدم وجود أخطاء. يمكنك كتابة اختبارات تستدعي الدوال فقط دون التحقق من أي شيء. التغطية هي مقياس كمي. جودة الاختبارات هي مقياس نوعي. استخدم كلا النهجين.
\n\nالقياس الأساسي: go test -cover
\n\nلنبدأ بالأبسط. Go لديه دعم مدمج للتغطية مباشرة في أداة go test. دعنا ننشئ مشروعًا بسيطًا ونرى كيف يعمل هذا.
أنشئ ملفًا باسم math.go:
package main\n\nfunc Add(a, b int) int {\n return a + b\n}\n\nfunc Subtract(a, b int) int {\n return a - b\n}\n\nfunc Multiply(a, b int) int {\n return a * b\n}\n\nfunc Divide(a, b int) (int, error) {\n if b == 0 {\n return 0, nil // خطأ: يجب أن يكون return 0, errors.New("division by zero")\n }\n return a / b, nil\n}\n\nوالآن — الاختبار (math_test.go):
package main\n\nimport "testing"\n\nfunc TestAdd(t *testing.T) {\n result := Add(2, 3)\n if result != 5 {\n t.Errorf("expected 5, got %d", result)\n }\n}\n\nfunc TestSubtract(t *testing.T) {\n result := Subtract(10, 4)\n if result != 6 {\n t.Errorf("expected 6, got %d", result)\n }\n}\n\n// لا نختبر Multiply و Divide عمدًا\n\nالآن شغّل الاختبارات مع العلم -cover:
go test -cover\n\nسيكون الإخراج مشابهًا لهذا:
\n\nok example/math 0.002s coverage: 50.0% of statements\n\nهذا صحيح — تمت تغطية 50% من الكود، لأن Multiply و Divide لا يتم اختبارهما. لكن هذا مجرد رقم إجمالي. ماذا لو أردنا رؤية ملف تعريف تغطية مفصل؟
ملف تعريف التغطية: go test -coverprofile
\n\nالعلم -coverprofile يحفظ معلومات مفصلة عن التغطية في ملف:
go test -coverprofile=coverage.out\n\nالآن ظهر ملف باسم coverage.out في المجلد. افتحه — إنه تنسيق نصي، حيث يظهر كل سطر ما إذا تم تنفيذ تعليمة معينة من الكود أم لا. لكن قراءته يدويًا مملة. دعنا ننتقل إلى التصور.
تقرير HTML: go tool cover -html
\n\nالطريقة الأكثر ملاءمة لتحليل التغطية هي تقرير HTML. يبرز الكود المنفذ باللون الأخضر، والكود غير المنفذ باللون الأحمر.
\n\ngo tool cove