الاختبار والتكامل
جزء من قسم Object Oriented Programming في رحلة GO على Coddy — الدرس 104 من 107.
التحدي
سهلدعونا نكمل دورة نظام إدارة المكتبة الخاص بنا من خلال كتابة اختبارات تتحقق من أن كل شيء يعمل بشكل صحيح! ستقوم بإنشاء ملف اختبار يتحقق من الوظائف الأساسية لمكتبتك — مما يضمن إمكانية استعارة الكتب وإعادتها بشكل صحيح، ومعالجة حالات الخطأ بشكل سليم.
ستقوم بتنظيم الكود الخاص بك عبر خمسة ملفات:
book.go: هيكلBookالخاص بك مع حقولIDوTitleوAuthorوISBNوAvailable. قم بتضمين منشئNewBookالذي يقوم بتهيئة الكتب كمتوفرة.user.go: هيكلUserالخاص بك مع حقولIDوNameوEmailوBorrowedBooks. قم بتضمين منشئNewUser.library.go: هيكلLibraryالخاص بك مع خرائط (maps) للكتب والمستخدمين، بالإضافة إلى دوال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
لكل اختبار، استخدم بيانات الاختبار القياسية هذه:
- الكتاب: ID
B001، العنوانGo Programming، المؤلفJohn Doe، ISBN123-456 - المستخدم: ID
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)
// تجهيزات الاختبار القياسية
// Book: المعرف "B001"، العنوان "Go Programming"، المؤلف "John Doe"، الرقم الدولي المعياري للكتاب ISBN "123-456"
// User: المعرف "U001"، الاسم "Alice"، البريد الإلكتروني "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")
}
}
جميع دروس Object Oriented Programming
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 الكتاب والمستخدم