الاختبار والتكامل
جزء من قسم البرمجة كائنية التوجه في رحلة GO على Coddy. الدرس 104 من 107.
التحدي
سهللنُكمل دورة نظام إدارة المكتبة بكتابة اختبارات تتحقق من أن كل شيء يعمل بشكل صحيح! ستنشئ ملف اختبار يتحقق من الوظائف الأساسية لمكتبتك: ضمان إمكانية استعارة الكتب وإرجاعها بشكل صحيح، ومعالجة حالات الخطأ بصورة سليمة.
ستنظّم شيفرتك عبر خمسة ملفات:
book.go: بنيةBookالخاصة بك، مع الحقولIDوTitleوAuthorوISBNوAvailable. أدرج المُنشئNewBookالذي يهيّئ الكتب على أنها متاحة.user.go: بنيةUserالخاصة بك، مع الحقولIDوNameوEmailوBorrowedBooks. أدرج المُنشئNewUser.library.go: بنيةLibraryالخاصة بك، مع خرائط للكتب والمستخدمين، إلى جانب أساليبNewLibraryوAddBookوAddUserوBorrowوReturn. يجب أن يعيد الأسلوبBorrowأخطاءً عند وجود مستخدم غير صالح، أو كتاب غير صالح، أو كتاب غير متاح. ويجب أن يعيد الأسلوبReturnأخطاءً عند وجود مستخدم غير صالح، أو كتاب غير صالح، أو كتاب لم تتم استعارته.library_test.go: هنا ستكتب دوال الاختبار! أنشئ اختبارات تتحقق مما يلي:TestBorrowSuccess: تحقّق من نجاح استعارة كتاب متاح (من دون إرجاع خطأ)، ومن أن الكتاب يصبح غير متاح، ومن إضافة معرّف الكتاب إلى قائمة الكتب المستعارة لدى المستخدمTestBorrowUnavailable: تحقّق من أن استعارة كتاب مُستعار بالفعل تعيد خطأًTestBorrowInvalidUser: تحقّق من أن الاستعارة باستخدام معرّف مستخدم غير موجود تعيد خطأًTestReturnSuccess: تحقّق من نجاح إرجاع كتاب مُستعار، ومن أن الكتاب يصبح متاحًا مرة أخرى، ومن إزالة معرّف الكتاب من قائمة الكتب المستعارة لدى المستخدم
يجب أن يهيّئ كل اختبار مكتبته الخاصة بالكتب والمستخدمين اللازمين، وينفّذ العملية، ويتحقق من النتائج باستخدام
t.Errorأوt.Errorfعند فشل التأكيدات.main.go: شغّل اختباراتك يدويًا وأبلغ عن النتائج. اقرأ اسم الاختبار المطلوب تنفيذه (borrow_successأوborrow_unavailableأوborrow_invalid_userأوreturn_success). وبناءً على اسم الاختبار، هيّئ السيناريو المناسب واطبعPASSإذا نجحت جميع التأكيدات، أوFAIL: [reason]إذا فشل أي تأكيد.
سيتم توفير الإدخال التالي:
- اسم اختبار:
borrow_successأوborrow_unavailableأوborrow_invalid_userأوreturn_success
لكل اختبار، استخدم بيانات الاختبار القياسية التالية:
- الكتاب: المعرّف
B001، العنوانGo Programming، المؤلفJohn Doe، ورقم ISBN123-456 - المستخدم: المعرّف
U001، الاسمAlice، البريد الإلكترونيalice@test.com
على سبيل المثال، عند تقديم:
borrow_successيجب أن يكون إخراجك:
PASSوعند تقديم:
borrow_unavailableيجب أن يكون إخراجك:
PASSوعند تقديم:
borrow_invalid_userيجب أن يكون إخراجك:
PASSوعند تقديم:
return_successيجب أن يكون إخراجك:
PASSبالنسبة إلى borrow_success: أنشئ مكتبة، وأضف كتابًا ومستخدمًا، واستعر الكتاب، وتحقّق من عدم وجود خطأ، وتحقّق من أن الكتاب غير متاح، وتحقّق من أن المستخدم لديه الكتاب في قائمة الكتب المستعارة الخاصة به.
بالنسبة إلى borrow_unavailable: أنشئ مكتبة، وأضف كتابًا ومستخدمًا، واضبط قيمة Available للكتاب على false، وحاول استعارة الكتاب، وتحقّق من إرجاع خطأ.
بالنسبة إلى borrow_invalid_user: أنشئ مكتبة، وأضف الكتاب فقط (من دون مستخدم)، وحاول الاستعارة باستخدام معرّف المستخدم U001، وتحقّق من إرجاع خطأ.
بالنسبة إلى return_success: أنشئ مكتبة، وأضف كتابًا ومستخدمًا، واستعر الكتاب أولًا، ثم أعده، وتحقّق من عدم وجود خطأ، وتحقّق من أن الكتاب متاح مرة أخرى، وتحقّق من أن قائمة الكتب المستعارة لدى المستخدم فارغة.
تضمن كتابة الاختبارات أن يتصرف نظام مكتبتك بشكل صحيح، وتمنحك الثقة لإجراء تغييرات من دون تعطيل الوظائف الحالية!
جرّب بنفسك
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
testName, _ := reader.ReadString('\n')
testName = strings.TrimSpace(testName)
// تجهيزات الاختبار القياسية
// كتاب: ID "B001", Title "Go Programming", Author "John Doe", ISBN "123-456"
// مستخدم: ID "U001", Name "Alice", Email "alice@test.com"
switch testName {
case "borrow_success":
// TODO: اختبر أن استعارة كتاب متاح تنجح
// 1. أنشئ مكتبة، أضف كتابًا ومستخدمًا
// 2. استعر الكتاب
// 3. تحقق: لا خطأ، الكتاب غير متاح، المستخدم لديه الكتاب في القائمة
// اطبع "PASS" إذا نجحت كلها، أو "FAIL: [reason]" إذا فشل أي منها
fmt.Println("FAIL: not implemented")
case "borrow_unavailable":
// TODO: اختبر أن استعارة كتاب غير متاح تُرجع خطأً
// 1. أنشئ مكتبة، أضف كتابًا ومستخدمًا
// 2. عيّن Available للكتاب إلى false
// 3. حاول الاستعارة
// 4. تحقق من إرجاع خطأ
fmt.Println("FAIL: not implemented")
case "borrow_invalid_user":
// TODO: اختبر أن الاستعارة بمستخدم غير صالح تُرجع خطأ
// 1. أنشئ مكتبة، أضف الكتاب فقط (بدون مستخدم)
// 2. حاول الاستعارة بمعرف المستخدم "U001"
// 3. تحقق من إرجاع خطأ
fmt.Println("FAIL: not implemented")
case "return_success":
// TODO: اختبر أن إرجاع كتاب مستعار ينجح
// 1. أنشئ مكتبة، أضف كتابًا ومستخدمًا
// 2. استعر الكتاب أولاً
// 3. أرجع الكتاب
// 4. تحقق: لا خطأ، الكتاب متاح، قائمة المستخدم فارغة
fmt.Println("FAIL: not implemented")
default:
fmt.Println("FAIL: unknown test")
}
}
جميع دروس البرمجة كائنية التوجه
1أساسيات الـ OOP في Go
الملفات الخارجيةمساحة العمل والـ Modules في Goالـ Packages والـ Importsالأسماء المصدرة مقابل غير المصدرةمقدمة إلى الـ OOP في Goالـ Structs كـ Classesتعريف الـ Methods في الـ Structsالـ Pointer Receivers مقابل الـ Value Receiversتهيئة الـ Structدوال الـ Constructorمراجعة - آلة حاسبة بسيطة4الواجهات
مقدمة في الواجهاتالتنفيذ الضمنيالواجهة كعقدالواجهة الفارغة (any)تأكيد النوع (Type Assertion)تبديل النوع (Type Switch)تركيب الواجهاتواجهات Stringer و Errorمراجعة - حاسبة الأشكال7التغليف
الحقول المصدرة وغير المصدرةالتغليف على مستوى الحزمةدوال الـ Getter والـ Setterإخفاء المعلومات في Goملخص - سجلات الطلاب10الأنواع العامة (Go 1.18+)
مقدمة في الأنواع العامةمعاملات الأنواعقيود الأنواعالـ Structs العامةحل بديل للـ Methods العامةملخص - المجموعات العامة13أنماط التصميم - الجزء الأول
مقدمة في أنماط التصميمنمط Singletonنمط Factoryنمط Abstract Factoryنمط Observerنمط Strategy2تعمق في الأنواع و Structs
الأنواع الأساسية والمركبةتعريفات الأنواع المخصصةStruct TagsStructs مجهولةStructs متداخلةالقيم الصفرية والافتراضيةمراجعة - دفتر العناوين5التركيب بدلاً من الوراثة
لماذا لا تدعم Go الوراثةأساسيات تضمين الـ Structترقية الـ Methodتضمين عدة Structsالتضمين مقابل التجميعحجب الـ Methods المضمنةملخص - الهيكل الهرمي للموظفين8معالجة الأخطاء و OOP
واجهة errorأنواع الأخطاء المخصصةتغليف الأخطاء (fmt.Errorf)أخطاء Sentinelerrors.Is() و errors.As()Panic و Defer و Recoverملخص - File Parser11المكتبة القياسية والبرمجة كائنية التوجه (OOP)
io.Reader و io.Writerواجهة sort.Interfaceواجهة fmt.Stringerencoding/json مع Structsواجهة http.Handlerمراجعة - نماذج REST API14أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط طريقة القالبنمط الحالةنمط التركيبMiddleware كنمط مزين3المؤشرات والذاكرة
أساسيات المؤشرات في Goالمؤشرات إلى الـ Structsالتمرير بالقيمة مقابل التمرير بالمرجعدالة ()newGarbage Collection في Goملخص - بناء Linked List6تعدد الأشكال في Go
تعدد الأشكال عبر InterfacesDuck Typing في Goقواعد استيفاء الـ Interfaceمجموعات متعددة الأشكالحقن التبعيةمراجعة - معالج الدفع9التزامن والبرمجة كائنية التوجه (OOP)
أساسيات الـ Goroutinesالقنوات (Channels) والاتصالالقنوات المخزنة (Buffered) مقابل غير المخزنةجملة Selectsync.Mutex و sync.RWMutexsync.WaitGroupتصميم الـ Structs الآمنة للخيوط (Thread-Safe)مراجعة - Worker Pool12مفاهيم OOP المتقدمة
نمط Functional Optionsنمط Builder في Goتسلسل الدوال (Method Chaining)الأسماء المستعارة للأنواع مقابل التعريفاتأساسيات الـ Reflectionنظرة عامة على Code Generation15مشروع: إدارة المكتبة
نظرة عامة وهيكل المشروعهياكل Structs الكتاب والمستخدمتدرّب بنفسك: مترجم Go عبر الإنترنت