gomock في Go: دليل شامل لاختبار الواجهات (Mocking Interfaces)
1. ما هي gomock ولماذا تحتاجها؟
في تطوير تطبيقات Go الحديثة، يلعب الاختبار دورًا محوريًا. لكن غالبًا ما يعتمد الكود على أنظمة خارجية مثل قواعد البيانات، عملاء HTTP، أنظمة الملفات، أو خدمات مصغرة أخرى. اختبار هذا الكود بمعزل عن هذه التبعيات صعب، لأنها تتطلب بيئة تشغيل حقيقية. هنا يأتي دور gomock — مكتبة قوية لإنشاء واستخدام الكائنات الوهمية (Mocks) لواجهات Go.
تتيح لك gomock إنشاء تطبيقات للواجهات تتصرف بشكل متوقع: تُرجع قيمًا محددة، تتحقق من ترتيب الاستدعاءات، تحسب عدد المرات، بل وتحاكي الأخطاء. هذا يجعل اختبارات الوحدة سريعة، محددة النتائج، ومستقلة عن الموارد الخارجية. تتكامل المكتبة بشكل وثيق مع حزمة testing المدمجة، وتُعتبر المعيار الفعلي لإنشاء الكائنات الوهمية في مجتمع Go.
القيمة الأساسية لـ gomock هي أنك تختبر سلوك الكود، وليس تنفيذه. أنت تتحقق من أن خدمتك تستدعي دوال التبعيات بالوسائط الصحيحة وتتعامل مع النتائج بشكل صحيح. هذا مهم بشكل خاص عند اتباع مبادئ SOLID ونمط "حقن التبعيات" (Dependency Injection).
2. التثبيت
للعمل مع gomock، ستحتاج إلى تثبيت مكونين:
- مكتبة gomock — تحتوي على بيئة التشغيل للعمل مع الكائنات الوهمية.
- أداة mockgen — مولد كود الكائنات الوهمية من الواجهات.
يتم التثبيت عبر مدير الحزم القياسي في Go:
# تثبيت المكتبة
go get github.com/golang/mock/gomock
# تثبيت أداة mockgen
go install github.com/golang/mock/mockgen@v1.6.0
بعد التثبيت، تأكد من أن mockgen متاح في PATH الخاص بك. يمكنك التحقق بالأمر:
mockgen --version
إذا كنت تستخدم Go 1.16+، يُنصح بإضافة mockgen إلى ملف tools.go لإدارة الإصدارات:
// tools.go
// +build tools
package tools
import (
_ "github.com/golang/mock/mockgen"
)
3. بداية سريعة — مثال عملي بسيط
لننظر إلى مثال بسيط. لنفترض أن لدينا واجهة Greeter نريد إنشاء كائن وهمي لها.
// greeter.go
package main
// Greeter — الواجهة التي سننشئ لها كائنًا وهميًا
type Greeter interface {
Greet(name string) string
}
// Service يستخدم Greeter
type Service struct {
greeter Greeter
}
func NewService(g Greeter) *Service {
return &Service{greeter: g}
}
func (s *Service) SayHello(name string) string {
return s.greeter.Greet(name)
}
أولاً، لننشئ الكائن الوهمي:
mockgen -source=greeter.go -destination=mock_greeter.go -package=main
الآن، لنكتب الاختبار:
// greeter_test.go
package main
import (
"testing"
"github.com/golang/mock/gomock"
)
func TestSayHello(t *testing.T) {
// إنشاء وحدة تحكم gomock
ctrl := gomock.NewController(t)
defer ctrl.Finish()
// إنشاء كائن وهمي لـ Greeter
mockGreeter := NewMockGreeter(ctrl)
// إعداد التوقع: عند استدعاء Greet("Alice")، أعد "Hello, Alice!"
mockGreeter.EXPECT().Greet("Alice").Return("Hello, Alice!")
// إنشاء الخدمة باستخدام الكائن الوهمي
service := NewService(mockGreeter)
// استدعاء الدالة المختبرة
result := service.SayHello("Alice")
// التحقق من النتيجة
if result != "Hello, Alice!" {
t.Errorf("توقعنا 'Hello, Alice!'، لكن حصلنا على '%s'", result)
}
}
شغّل الاختبار:
go test -v
سترى أن الاختبار ينجح. الكائن الوهمي تحقق تلقائيًا من أن الدالة Greet استُدعيت بالوسيط الصحيح وأرجعت القيمة المتوقعة.