الاختبار في Go: Unit، Integration، E2E — دليل شامل
الاختبار هو جزء لا يتجزأ من تطوير البرمجيات عالية الجودة. في لغة Go (Golang)، تم تضمين الاختبار على مستوى المكتبة القياسية، مما يجعله بسيطًا وفعالًا. في هذه المقالة، سنقوم بتحليل المستويات الثلاثة الرئيسية للاختبار: اختبارات الوحدة (unit)، واختبارات التكامل (integration)، والاختبارات الشاملة (e2e). ستتعلم كيفية كتابتها، ومتى تستخدمها، وما هي الأدوات التي يجب استخدامها.
لماذا يعتبر الاختبار في Go مهمًا جدًا؟
تم إنشاء Go مع التركيز على البساطة والموثوقية. تتيح الحزمة المدمجة testing وأداة go test إضافة الاختبارات بسهولة إلى أي مشروع. تلتزم فريق Go بفلسفة: "إذا لم يتم اختبار الكود، فهو لا يعمل". يساعد الاختبار في:
- اكتشاف الأخطاء في المراحل المبكرة من التطوير
- تبسيط إعادة هيكلة الكود وصيانته
- توثيق سلوك الدوال والوحدات
- زيادة الثقة في استقرار التطبيق
اختبار الوحدة (Unit Testing) في Go
تتحقق اختبارات الوحدة (unit tests) من عمل الدوال أو الطرق أو الهياكل الفردية بشكل منفصل عن التبعيات الخارجية. في Go، تُكتب في ملفات ذات اللاحقة _test.go.
أساسيات اختبارات الوحدة
لننظر إلى مثال بسيط. لنفترض أن لدينا دالة جمع:
// math.gopackage main
func Add(a, b int) int { return a + b}سيبدو اختبار هذه الدالة كالتالي:
// math_test.gopackage main
import "testing"
func TestAdd(t *testing.T) { result := Add(2, 3) expected := 5 if result != expected { t.Errorf("Add(2, 3) = %d; want %d", result, expected) }}تشغيل الاختبار: go test -v
الاختبارات الجدولية (Table-driven tests)
يشجع Go على استخدام الاختبارات الجدولية للتحقق من سيناريوهات متعددة:
func TestAddTableDriven(t *testing.T) { tests := []struct { name string a, b int want int }{ {"positive numbers", 2, 3, 5}, {"negative numbers", -1, -2, -3}, {"zero", 0, 0, 0}, {"mixed", -5, 10, 5}, }
for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := Add(tt.a, tt.b) if got != tt.want { t.Errorf("Add(%d, %d) = %d; want %d", tt.a, tt.b, got, tt.want) } }) }}الاختبار باستخدام الكائنات الوهمية (Mock)
لعزل اختبارات الوحدة، غالبًا ما تكون هناك حاجة إلى كائنات وهمية (mocks). في Go، يمكن استخدام الواجهات (interfaces) والمكتبات مثل gomock أو testify/mock.
// تعريف الواجهةtype UserRepository interface { GetUser(id int) (User, error)}
// اختبار باستخدام testifyfunc TestGetUserName(t *testing.T) { mockRepo := new(MockUserRepository) mockRepo.On("GetUser", 1).Return(User{Name: "Alice"}, nil)
service := NewUserService(mockRepo) name, err := service.GetUserName(1)
assert.NoError(t, err) assert.Equal(t, "Alice", name) mockRepo.AssertExpectations(t)}اختبار التكامل (Integration Testing) في Go
تتحقق اختبارات التكامل من التفاعل بين مكونات النظام: قواعد البيانات، واجهات برمجة التطبيقات (APIs)، أنظمة الملفات، والخدمات الخارجية الأخرى. في Go، من الشائع وضعها في حزم منفصلة أو استخدام build tags.
الاختبار مع قاعدة البيانات
لاختبار العمل مع قاعدة البيانات، غالبًا ما يتم استخدام testcontainers أو قواعد بيانات مؤقتة:
// integration_test.go (مع build tag)//go:build integration
package integration
import ( "database/sql" "testing" _ "github.com/lib/pq")
func TestUserRepository(t *testing.T) { // الاتصال بقاعدة بيانات الاختبار db, err := sql.Open("postgres", "host=localhost port=
```