اختبارات Go: الوحدة، التكامل، e2e من الألف إلى الياء

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: لماذا تعتبر الاختبارات في Go ضرورة؟

\n

Go (Golang) هي لغة برمجة حديثة صُممت لبناء أنظمة موثوقة وقابلة للتوسع. ومع ذلك، حتى الكود الأكثر أناقة ليس محصنًا ضد الأخطاء. ولهذا السبب، تعتبر الاختبارات جزءًا لا يتجزأ من التطوير في Go. توفر الحزمة المدمجة testing مجموعة أدوات قوية لكتابة اختبارات الوحدة، واختبارات التكامل، وحتى اختبارات end-to-end (e2e).

\n

في هذه المقالة، سنستعرض جميع مستويات الاختبارات في Go: من اختبارات الوحدة البسيطة إلى سيناريوهات e2e المعقدة. ستتعلم كيفية هيكلة الاختبارات بشكل صحيح، واستخدام الموكات (mocks)، وكتابة اختبارات table-driven، وإعداد اختبارات التكامل مع التبعيات الحقيقية. ستكون المادة مفيدة لكل من المبتدئين والمطورين ذوي الخبرة الذين يرغبون في تنظيم معرفتهم.

\n\n

1. اختبارات الوحدة في Go: الأساسيات

\n

تتحقق اختبارات الوحدة من عمل الدوال أو الطرق الفردية بمعزل عن التبعيات الخارجية. في Go، تُستخدم الحزمة القياسية testing لهذا الغرض. القواعد الأساسية: يجب تسمية ملفات الاختبار *_test.go، ويجب أن تبدأ دوال الاختبار بـ Test.

\n\n

1.1. اختبار وحدة بسيط

\n

لننظر إلى دالة جمع رقمين:

\n
// math.go\npackage math\n\nfunc Add(a, b int) int {\n    return a + b\n}
\n

الاختبار الخاص بها:

\n
// math_test.go\npackage math\n\nimport "testing"\n\nfunc TestAdd(t *testing.T) {\n    result := Add(2, 3)\n    expected := 5\n    if result != expected {\n        t.Errorf("Add(2, 3) = %d; want %d", result, expected)\n    }\n}
\n

تشغيل الاختبارات: go test ./... أو go test -v للحصول على إخراج مفصل.

\n\n

1.2. اختبارات Table-driven (اختبارات جدولية)

\n

يستخدم مجتمع Go بشكل نشط نهج table-driven للتحقق من حالات متعددة:

\n
func TestAddTableDriven(t *testing.T) {\n    tests := []struct {\n        name string\n        a, b int\n        want int\n    }{\n        {"positive", 2, 3, 5},\n        {"negative", -1, -2, -3},\n        {"zero", 0, 0, 0},\n    }\n    for _, tt := range tests {\n        t.Run(tt.name, func(t *testing.T) {\n            if got := Add(tt.a, tt.b); got != tt.want {\n                t.Errorf("Add() = %d, want %d", got, tt.want)\n            }\n        })\n    }\n}
\n

يجعل هذا النهج الاختبارات سهلة القراءة وقابلة للتوسع.

\n\n

1.3. اختبار الأخطاء

\n

بالنسبة للدوال التي تُرجع أخطاء، استخدم t.Fatal أو t.Errorf:

\n
func TestDivide(t *testing.T) {\n    _, err := Divide(10, 0)\n    if err == nil {\n        t.Fatal("expected error for division by zero")\n    }\n}
\n\n

2. اختبارات التكامل: العمل مع التبعيات

\n

تتحقق اختبارات التكامل من تفاعل المكونات: قواعد البيانات، واجهات API، نظام الملفات. في Go، يتم فصلها عادةً عن اختبارات الوحدة باستخدام build tags أو هيكل حزم منفصل.

\n\n

2.1. استخدام build tags

\n

أنشئ ملفًا مع الوسم //go:build integration في البداية:

\n
//go:build integration\n\npackage db\n\nimport (\n    "testing"\n    "database/sql"\n    _ "github.com/lib/pq"\n)\n\nfunc TestPostgresConnection(t *testing.T) {\n    dsn := "host=localhost port=5432 user=test password=test dbname=test sslmode=disable"\n    db, err := sql.Open("postgres", dsn)\n    if err != nil {\n        t.Fatalf("failed to open db: %v", err)\n    }\n    defer db.Close()\n    \n    if err := db.Ping(); err != nil {\n        t.Fatalf("failed to ping db: %v", err)\n    }\n}
\n

تشغيل اختبارات التكامل فقط: go test -tags=integration ./...

\n\n

2.2. الموكات (Mocks) والنماذج الوهمية (Stubs)

\n

لعزل الاختبارات، استخدم الواجهات والموكات. مثال مع المكتبة الشهيرة gomock:

\n
// user.go\ntype UserRepository interface {\n    GetUser(id int) (*Us                

المدونات

توصيات الكتب