دروس الوحدة (1/5)
حزمة "الاختبار".
في Go، تكون الاختبارات جزءًا من stdlib: لا توجد مكتبة خارجية، ولا يوجد إطار عمل لتكوينه. كل ما تحتاجه هو ملف *_test.go بجوار الرمز، وبعض وظائف TestXxx، والأمر go test.
الاتفاقيات الأساسية
- تتم تسمية ملفات الاختبار
<something>_test.goوهي موجودة في نفس الحزمة مثل الكود الذي تختبره (أو في حزمة<name>_testلـ "اختبارات الصندوق الأسود"). - تحتوي وظائف الاختبار على توقيع دقيق:
func TestXxx(t *testing.T)حيث يبدأXxxبحرف كبير. - قمت باستيراد
testingمن ملف stdlib. - لا
assertEquals: تستخدمif got != want { t.Errorf(...) }مع أفعالfmt.
// math.go
package math
func Sum(a, b int) int { return a + b }
// math_test.go
package math
import "testing"
func TestSum(t *testing.T) {
got := Sum(2, 3)
if got != 5 {
t.Errorf("Sum(2,3) = %d; voglio %d", got, 5)
}
}تشغيله مع:
go test ./... # all packages in the module
go test -v ./pkg # verbose: prints test names
go test -run TestSum # only tests matching the regext.Error مقابل t.Fatal
هذان هما الفعلان الأساسيان للإشارة إلى الفشل:
| الطريقة | تأثير |
|---|---|
| محمي_INLINE_13 | يتم التسجيل ولكنه لا يفشل (مرئي فقط مع -v أو عند الفشل). |
| محمي_INLINE_15 | يسجل ويضع علامة فشل ويستمر في وظيفة الاختبار. |
| محمي_INLINE_16 | مثل Error بالتنسيق. |
| محمي_INLINE_18 | السجلات، تشير إلى فشل، توقف الاختبار (يستدعي runtime.Goexit). |
| محمي_INLINE_20 | مثل Fatal بالتنسيق. |
القاعدة الأساسية: استخدم Fatal عندما لا تكون المتابعة منطقية (على سبيل المثال، فشل الإعداد، أو عدم مرجعية مؤشر الصفر الوشيك)؛ بخلاف ذلك Error، والذي يتيح لك رؤية جميع حالات الفشل في عملية تشغيل واحدة.
func TestOpen(t *testing.T) {
f, err := os.Open("fixtures/sample.txt")
if err != nil {
t.Fatal(err) // if it doesn't open, the next steps would fail on nil
}
defer f.Close()
// ... assert on content with t.Errorf
}الإعداد والتفكيك باستخدام t.Cleanup
لتحرير الموارد في نهاية الاختبار (أو الاختبار الفرعي)، استخدم t.Cleanup بدلاً من defer:
func TestDB(t *testing.T) {
db := newTestDB(t)
t.Cleanup(func() { db.Close() })
// ... test
}الميزة التي يتميز بها defer: يمكن للمساعد الذي يقوم بإنشاء db تسجيل عملية التنظيف داخليًا، لذلك لا يحتاج المتصلون إلى تذكرها.
مساعدين الاختبار
تقوم الطريقة t.Helper() بوضع علامة على دالة باعتبارها "مساعدة": عندما يفشل الاختبار، فإن تتبع المكدس يتخطى الوظيفة المساعدة ويشير مباشرة إلى المتصل:
func mustParseInt(t *testing.T, s string) int {
t.Helper()
n, err := strconv.Atoi(s)
if err != nil {
t.Fatalf("parse %q: %v", s, err)
}
return n
}تمارين
حدد الدالة TestSum التي تتحقق من Sum(2,3) == 5 باستخدام t.Errorf برسالة منسقة.
الحل متاح بعد 3 من المحاولات
في TestDiv، استخدم t.Fatal لإيقاف الاختبار فورًا إذا قام Div بإرجاع قيمة غير متوقعة.
الحل متاح بعد 3 من المحاولات
ما هو الفرق الأساسي بين t.Error وt.Fatal؟
if err != nil {
t.???(err)
}