عندما يتحول الكود إلى قصة
\nتخيل: أنت تكتب كودًا بلغة Go، وتشغل الاختبارات - شريط أخضر. لكن المدير ينظر إلى t.Errorf الخاص بك ولا يفهم ما الذي تعطل بالضبط. يقول العمل: "اجعل المستخدم قادرًا على التسجيل"، والمطور يترجم هذا إلى "POST /api/v1/user مع التحقق من البريد الإلكتروني". الفجوة بين اللغة التقنية واللغة البشرية هي الصداع الرئيسي للعديد من المشاريع.
الحل موجود - BDD (التطوير القائم على السلوك) على Go. هذه ليست مجرد اختبارات. إنها جسر بين الكود ومنطق العمل. في هذه المقالة، سنشرح كيفية كتابة اختبارات BDD على Go باستخدام أمثلة حقيقية، ولماذا سيكون مدير منتجك ممتنًا لك.
\n\nما هو BDD ولماذا Go؟
\nالتطوير القائم على السلوك (Behaviour-Driven Development) هو تطور لـ TDD. إذا كان TDD يركز على "كيف" (كيفية تنفيذ الوظيفة)، فإن BDD يجيب على "ماذا" (ما يجب أن يفعله النظام من وجهة نظر المستخدم).
\nGo مثالي لـ BDD بفضل بساطته، وحزمة testing المدمجة، والأطر القوية مثل Ginkgo و Godog. يستخدم مجتمع Go بنشاط BDD للخدمات المصغرة، وواجهات API، وحتى أدوات سطر الأوامر.
المبادئ الأساسية لـ BDD على Go
\n- \n
- اللغة الموحدة (Ubiquitous Language) - تُكتب السيناريوهات بلغة مفهومة للعمل باللغة الإنجليزية أو العربية. \n
- Given-When-Then - هيكل أي سيناريو: الافتراضات → الإجراء → النتيجة المتوقعة. \n
- الأتمتة - تتحول السيناريوهات إلى اختبارات قابلة للتنفيذ بلغة Go. \n
أدوات BDD في Go
\nيعتمد اختيار الإطار على كيفية رغبتك في وصف السيناريوهات. إليك طريقتان رئيسيتان:
\n\n1. Ginkgo + Gomega (لمطوري Go)
\nGinkgo هو إطار BDD يُكتب بلغة Go النقية. تبدو السيناريوهات ككود Go مع أوصاف قابلة للقراءة. Gomega هي مكتبة مطابقات للتأكيدات.
\nالمزايا: تحكم كامل في الكود، تكامل ممتاز مع أدوات Go، دعم الاختبارات غير المتزامنة.
\n\n2. Godog (Cucumber لـ Go)
\nGodog هو تطبيق Cucumber على Go. تكتب السيناريوهات بلغة Gherkin (ملفات Feature بلغة طبيعية)، ثم تنفذ الخطوات بلغة Go.
\nالمزايا: حتى غير المبرمجين يمكنهم قراءة السيناريوهات، سهولة تغيير المنطق دون تعديل الكود.
\n\nالتطبيق العملي: كتابة اختبار BDD على Go باستخدام Ginkgo
\nلنقم بإنشاء خدمة بسيطة - سلة التسوق لمتجر إلكتروني. سنكتب اختبار BDD يتحقق من إضافة منتج.
\n\nالخطوة 1: تثبيت Ginkgo
\ngo get github.com/onsi/ginkgo/v2\ngo get github.com/onsi/gomega\n\nالخطوة 2: تهيئة حزمة الاختبار
\ncd mycart\nginkgo bootstrap\nيتم إنشاء ملف mycart_suite_test.go.
الخطوة 3: كتابة السيناريو
\nلننشئ ملف cart_test.go:
package mycart_test\n\nimport (\n . "github.com/onsi/ginkgo/v2"\n . "github.com/onsi/gomega"\n "mycart"\n)\n\nvar _ = Describe("السلة", func() {\n var cart *mycart.Cart\n\n BeforeEach(func() {\n cart = mycart.NewCart()\n })\n\n Describe("إضافة منتج", func() {\n Context("مع معرف وسعر صحيحين", func() {\n It("يجب أن تزيد عدد العناصر بمقدار 1", func() {\n cart.AddItem("sku-123", 100.0)\n Expect(cart.TotalItems()).To(Equal(1))\n })\n\n It("يجب أن تحسب المجموع الإجمالي بشكل صحيح", func() {\n cart.AddItem("sku-123", 100.0)\n cart.AddItem("sku-456", 250.0)\n Expect(cart.TotalPrice()).To(BeNumerically("~", 350.0, 0.01))\n })\n })\n\n Context("مع منتج موجود بالفعل", func() {\n It("يجب أن تزيد الكمية، وليس إضافة عنصر جديد", func() {\n cart.