مقدمة: لماذا الاختبار هو أساس تطبيق Swift الموثوق
\n\nيتطلب التطوير لنظامي iOS وmacOS موثوقية عالية للكود. قد يكلف الخطأ في منطق عمل التطبيق تجربة المستخدم، وفي المشاريع التجارية قد يكلف المال. اختبارات Swift ليست مجرد "أسلوب حسن"، بل هي مرحلة إلزامية في التطوير. فهي تسمح باكتشاف الأخطاء في المراحل المبكرة، وتبسيط إعادة الهيكلة، ورفع جودة الكود.
\n\nفي هذه المقالة، سنستعرض ثلاثة مستويات من الاختبارات: الوحدة (unit)، التكامل (integration)، وE2E (الشاملة). ستتعرف على الفروق بينها، ومتى تستخدم كل منها، وسترى أمثلة عملية بلغة Swift باستخدام إطار العمل XCTest.
1. اختبارات الوحدة في Swift: الأساس
\n\nتختبر اختبارات الوحدة الوحدات المنفردة (الدوال، الطرق، الفئات) بشكل منعزل. هدفها الرئيسي هو التأكد من أن كل "وحدة" من الكود تعمل بشكل صحيح.
\n\nإعداد XCTest
\n\nXCTest مدمج في Xcode. لإنشاء هدف اختبار:
\n- \n
- افتح المشروع في Xcode. \n
- اختر File → New → Target. \n
- اختر Unit Testing Bundle. \n
بعد الإنشاء، ستحصل على ملف بالشكل YourAppTests.swift.
مثال لاختبار وحدة
\n\nلنفترض أن لدينا دالة لحساب الخصم:
\n\nfunc calculateDiscount(price: Double, discount: Double) -> Double {\n guard discount >= 0 && discount <= 100 else { return price }\n return price * (1 - discount / 100)\n}\n\n\nنكتب الاختبار:
\n\nimport XCTest\n@testable import YourApp\n\nclass DiscountTests: XCTestCase {\n func testCalculateDiscount_ValidInput() {\n let result = calculateDiscount(price: 1000, discount: 20)\n XCTAssertEqual(result, 800, accuracy: 0.01)\n }\n \n func testCalculateDiscount_InvalidDiscount() {\n let result = calculateDiscount(price: 500, discount: 150)\n XCTAssertEqual(result, 500)\n }\n}\n\n\nأفضل الممارسات لاختبارات الوحدة:
\n- \n
- اختبار واحد — فحص واحد. \n
- استخدم
setUp()لتهيئة الكائنات المشتركة. \n - تجنب الاعتماد على الشبكة، قاعدة البيانات أو واجهة المستخدم — استخدم الكائنات الوهمية (mocks). \n
2. اختبارات التكامل: التحقق من تفاعل المكونات
\n\nتختبر اختبارات التكامل كيفية عمل الوحدات المختلفة معًا. على سبيل المثال، تفاعل نموذج البيانات مع طبقة الشبكة أو قاعدة بيانات CoreData.
\n\nمثال: اختبار طلب شبكة
\n\nلننشئ خدمة بسيطة:
\n\nclass NetworkService {\n func fetchUser(completion: @escaping (Result<User, Error>) -> Void) {\n // طلب حقيقي إلى API\n }\n}\n\n\nيمكن لاختبار التكامل التحقق من أن الخدمة تعالج الاستجابة من الخادم الحقيقي (أو من خادم وهمي محلي) بشكل صحيح:
\n\nclass NetworkServiceIntegrationTests: XCTestCase {\n var service: NetworkService!\n \n override func setUp() {\n super.setUp()\n service = NetworkService()\n }\n \n func testFetchUser_ReturnsUser() {\n let expectation = self.expectation(description: "Fetch user")\n \n service.fetchUser { result in\n switch result {\n case .success(let user):\n XCTAssertNotNil(user.name)\n case .failure:\n XCTFail("Request failed")\n }\n expectation.fulfill()\n }\n \n waitForExpectations(timeout: 5)\n }\n}\n\n\nهام: اختبارات التكامل أبطأ من اختبارات الوحدة، لذلك يتم تشغيلها بشكل أقل (على سبيل المثال، قبل الدمج في الفرع الرئيسي).
\n\n3. اختبارات E2E (الشاملة) باستخدام XCUITest
\n\nتحاكي اختبارات E2E (End-to-End) إجراءات المستخدم: الضغط على الأزرار، إدخال النص، التحقق من عرض واجهة المستخدم. في Swift، يتم ذلك باستخدام