XCTest: المفاهيم الأساسية، فئات XCTestCase وكتابة الاختبارات

المؤلف: IT Sectr نُشر: 2026-04-08 وقت القراءة: 11 دق

XCTest هو إطار عمل من Apple للاختبارات الوحدوية والتكاملية للتطبيقات على iOS و macOS و watchOS و tvOS. XCTest جزء من Xcode ويدعم كتابة الاختبارات بلغة Swift و Objective-C. على عكس الأطر الخارجية (Quick, Nimble)، XCTest هو الحل الرسمي من Apple ومتكامل بالكامل مع Xcode Server و CI/CD. وفقًا لـ Apple Developer (2024)، يُستخدم XCTest في 94% من تطبيقات iOS من أفضل 100 في App Store. XCTest يوفر أساسًا ثابتًا لكتابة اختبارات الوحدة واختبارات واجهة المستخدم دون تبعيات خارجية.

الملامح الرئيسية

  • XCTest — إطار العمل الرسمي من Apple لاختبارات الوحدة واختبارات واجهة المستخدم بلغة Swift و Objective-C.
  • XCTestCase — الفئة الأساسية لجميع الاختبارات، والتي توفر setUp و tearDown وطرق التأكيد.
  • التأكيدات — XCTAssertTrue و XCTAssertEqual و XCTAssertNil وغيرها للتحقق من النتائج المتوقعة.
  • XCTestExpectation — آلية لاختبار الكود غير المتزامن مع انتظار التنفيذ.
  • اختبارات الأداء — قياس وقت تنفيذ الكود من خلال طريقة measure(metrics:) مع حدود.

ما هو XCTest؟

XCTest هو إطار عمل للاختبارات الوحدوية والتكاملية واختبارات واجهة المستخدم طورته Apple ومدمج في Xcode منذ الإصدار 5.0 (2013). حل XCTest محل OCUnit (SenTestingKit) وقدم واجهة برمجة تطبيقات حديثة بلغة Swift مع دعم الاختبارات غير المتزامنة واختبارات الأداء والتكامل مع Xcode Server. وفقًا لـ Swift.org (2024)، XCTest هو الأساس للاختبارات في جميع مشاريع Apple، بما في ذلك Swift Package Manager الذي يستخدم XCTest للتحقق الذاتي.

يعمل XCTest مع Xcode Test Navigator و Report Navigator، اللذين يعرضان شجرة الاختبارات وتاريخ التشغيل ويقارنان النتائج بين الإصدارات. Test Navigator يسمح بتشغيل اختبار واحد أو مجموعة اختبارات أو المجموعة بأكملها دون تعديل الكود. تظهر النتائج برموز خضراء (نجاح) وحمراء (فشل) وصفراء (تخطي). وفقًا لـ Apple WWDC (2024)، قام Xcode 16 بتحسين التنفيذ المتوازي للاختبارات بنسبة 40% باستخدام محاكيات متعددة.

يدعم XCTest المنصات: iOS 8.0+ و macOS 10.10+ و watchOS 2.0+ و tvOS 9.0+. كل منصة لها نفس واجهة برمجة التطبيقات، مما يسمح بكتابة اختبارات عبر المنصات. Swift Testing — إطار عمل جديد من Apple (تم الإعلان عنه في 2024) — سيكمل XCTest في المستقبل ولكنه لن يحل محله بالكامل. يظل XCTest إطار العمل الرئيسي للاختبارات في نظام Apple البيئي.

XCTestCase — الفئة الأساسية للاختبارات

XCTestCase هي الفئة الأساسية التي ترث منها جميع فئات الاختبار في XCTest. توفر دورة حياة الاختبار: يتم استدعاء `setUp()` قبل كل اختبار، و `tearDown()` بعد كل اختبار. يُستخدم setUp لتهيئة الكائنات والمحاكيات، و tearDown لتنظيف الموارد. setUpWithError و tearDownWithError يسمحان بمعالجة أخطاء التهيئة دون try-catch في كل اختبار.

يتم التعرف تلقائيًا على كل طريقة يبدأ اسمها بـ `test` بواسطة Xcode كاختبار. بدلاً من ذلك، يمكن استخدام الماكرو `@Test` (Swift Testing). يجب أن تكون أسماء الاختبارات وصفية: `testLoginWithValidCredentials` أفضل من `testLogin1`. توثيق الاختبارات من خلال التعليقات هو ممارسة جيدة، ولكن Xcode يسمح أيضًا بإضافة أوصاف عبر User-Defined Attributes.

swift
import XCTest

class UserServiceTests: XCTestCase {

    var sut: UserService!
    var mockSession: MockURLSession!

    override func setUp() {
        mockSession = MockURLSession()
        sut = UserService(session: mockSession)
    }

    override func tearDown() {
        sut = nil
        mockSession = nil
    }

    func testFetchUser_ReturnsDecodedUser() {
        let json = "{\"id\": 1, \"name\": \"Alice\"}"
        mockSession.setResponse(json)
        let user = try await sut.fetchUser(id: 1)
        XCTAssertEqual(user.name, "Alice")
    }
}

يظهر المثال أعلاه هيكل XCTestCase القياسي. sut (النظام قيد الاختبار) هو اصطلاح تسمية للكائن الذي يتم اختباره. MockURLSession يحل محل الشبكة الحقيقية، مما يسمح باختبار UserService بشكل معزول. مبدأ «اختبار واحد — تأكيد واحد» يبسط تصحيح الأخطاء: إذا فشل اختبار، يعرف المطور فورًا أي وظيفة معطلة. يجب أن يتحقق كل اختبار XCTestCase من سيناريو واحد أو تأكيد واحد.

التأكيدات في XCTest

مجموعة التأكيدات الأساسية

XCTAssertTrue و XCTAssertFalse هما تأكيدات أساسية للتحقق من القيم المنطقية. XCTAssertTrue(expression) ينجح إذا expression == true. XCTAssertEqual يتحقق من تساوي قيمتين مع دعم جميع الأنواع التي تطبق Equatable. للأعداد العشرية، يُستخدم XCTAssertEqual مع معامل accuracy لمراعاة دقة الحساب. وفقًا لـ Google Testing Blog (2024)، يغطي XCTAssertEqual 70% من جميع الفحوصات في مجموعة اختبارات نموذجية.

تأكيدات nil والأخطاء

XCTAssertNil و XCTAssertNotNil يتحققان من القيم الاختيارية للتأكد من أنها ليست nil. هذه التأكيدات حاسمة في Swift، حيث تُستخدم الأنواع الاختيارية على نطاق واسع. XCTAssertThrowsError يتحقق من أن الكود يلقي خطأ متوقعًا. XCTUnwrap هو تأكيد يفك تغليف قيمة اختيارية ويفشل برسالة واضحة إذا كانت القيمة nil. مقارنة السلاسل عبر XCTAssertEqual تستخدم المقارنة الحرفية وليس الدلالية. XCTAssertNoThrow هو التأكيد المقابل للتحقق من أن الكود لا يلقي خطأ.

التأكيدالغرضمثال
XCTAssertEqualالتحقق من التساويXCTAssertEqual(a, b)
XCTAssertTrueالتحقق من الصحةXCTAssertTrue(result)
XCTAssertNilالتحقق من nilXCTAssertNil(error)
XCTAssertThrowsErrorالتحقق من الخطأXCTAssertThrowsError(try parse(""))
XCTUnwrapفك تغليف optionalXCTUnwrap(value)

XCTestExpectation والاختبارات غير المتزامنة

XCTestExpectation هي آلية لاختبار الكود غير المتزامن. ينشئ الاختبار توقعًا باسم وصفي، ويمره إلى عملية غير متزامنة، ويستدعي `wait(for:timeout:)`. إذا لم يتم استيفاء التوقع خلال المهلة، يفشل الاختبار. المهلة الافتراضية هي 10 ثوانٍ، ولكن للعمليات السريعة يُوصى بتعيين 1–3 ثوانٍ لتسريع وقت الاختبار الإجمالي.

XCTWaiter هو بديل أكثر مرونة لـ wait(for:timeout:). يسمح XCTWaiter بانتظار توقعات متعددة، وتكوين ترتيب التنفيذ، ومعالجة المهلات برمجيًا. على عكس wait، يعيد XCTWaiter `XCTWaiter.Result` الذي يمكن تحليله. المفوض XCTWaiterDelegate يخطر بانتهاكات ترتيب التوقعات والمهلات.

swift
func testAsyncLogin() {
    let expectation = XCTestExpectation(description: "login")
    var resultUser: User?

    sut.login(email: "a@b.com", password: "123") { user in
        resultUser = user
        expectation.fulfill()
    }

    wait(for: [expectation], timeout: 3)
    XCTAssertNotNil(resultUser)
    XCTAssertEqual(resultUser?.email, "a@b.com")
}

في المثال، يُستخدم XCTestExpectation لاختبار تسجيل دخول غير متزامن. يتم استدعاء fulfill() داخل إغلاق callback، للإشارة إلى اكتمال العملية غير المتزامنة. إذا لم يتم استدعاء fulfill() في غضون 3 ثوانٍ، يفشل الاختبار بانتهاء المهلة. بعد الانتظار الناجح، يتم تنفيذ التأكيدات للتحقق من النتيجة. توقعات متعددة يمكن تمريرها كمصفوفة وانتظار اكتمالها جميعًا.

اختبارات الأداء مع XCTest

measure(metrics:) هي طريقة في XCTestCase لإنشاء اختبارات الأداء. يتم تشغيل كتلة الكود داخل measure 10 مرات متتالية، ويجمع XCTest الإحصائيات: متوسط الوقت، الوسيط، الانحراف المعياري. المقاييس هي مصفوفة من المقاييس المتعقبة: XCTClockMetric (الوقت)، XCTMemoryMetric (الذاكرة)، XCTStorageMetric (القرص)، و XCTCPUMetric (المعالج). وفقًا لـ Apple WWDC (2024)، اختبارات الأداء مع XCTCPUMetric مفيدة لاكتشاف الانحدارات في الخوارزميات.

الخط الأساسي لاختبارات الأداء يُحدد في Xcode Test Plan. إذا تجاوز وقت التنفيذ الخط الأساسي بنسبة مئوية محددة (الافتراضي 10%)، يعتبر الاختبار فاشلاً. يتم تحديث الخط الأساسي يدويًا بعد تأكيد أن تغيير الأداء متوقع. خطة الاختبار في Xcode تسمح بتجميع اختبارات الأداء حسب التكوينات: debug/release، أجهزة مختلفة، إصدارات iOS مختلفة.

swift
func testArraySortPerformance() {
    let numbers = (1...10000).shuffled()
    measure(metrics: [XCTClockMetric()]) {
        let _ = numbers.sorted()
    }
}

يقيس اختبار الأداء هذا وقت فرز مصفوفة من 10,000 عنصر. XCTClockMetric يلتقط وقت التنفيذ الفعلي. إذا زاد الوقت بعد تغيير خوارزمية الفرز بنسبة 10% أو أكثر، سيشير الاختبار إلى وجود انحدار. اختبارات أداء XCTest مفيدة بشكل خاص لـ: خوارزميات معالجة البيانات، عرض مكونات واجهة المستخدم، عمليات قاعدة البيانات، وطلبات الشبكة.

تنظيم الاختبارات وتكامل CI/CD

هيكل مشروع الاختبار

هيكل مشروع الاختبار في XCTest يتبع الاصطلاح: ملف اختبار واحد لكل فئة، يوضع في دليل منفصل `<TargetName>Tests`. تتوافق أسماء الملفات مع أسماء الفئات المختبرة مع اللاحقة `Tests`: `UserService.swift` → `UserServiceTests.swift`. يتم تكوين Test Targets في Xcode بشكل منفصل لاختبارات الوحدة واختبارات واجهة المستخدم، مما يسمح بتشغيلها بشكل مستقل. Schemes في Xcode تدير تكوين البناء ومجموعة الاختبارات المراد تشغيلها.

تكامل CI/CD

Xcode Cloud و GitHub Actions يدعمان تشغيل XCTest عبر `xcodebuild test -scheme App -testPlan SmokeTest`. يتضمن خط أنابيب CI: بناء → تشغيل اختبارات الوحدة → تشغيل اختبارات واجهة المستخدم → نشر التقرير. يتم إنشاء تقرير JUnit عبر `xcodebuild` مع الخيار `-resultBundlePath` ويمكن استيراده إلى أي أداة CI. تغطية الكود هي ميزة مدمجة في XCTest تُظهر أي أسطر الكود مغطاة بالاختبارات. الحد الأدنى لتغطية كود الإنتاج هو 70% للمنطق التجاري الحرج.

Xcode Cloud و GitHub Actions يدعمان تشغيل XCTest عبر `xcodebuild test -scheme App -testPlan SmokeTest`. يتضمن خط أنابيب CI: بناء → تشغيل اختبارات الوحدة → تشغيل اختبارات واجهة المستخدم → نشر التقرير. تقرير JUnit يتم إنشاؤه عبر `xcodebuild` مع الخيار `-resultBundlePath` ويمكن استيراده إلى أي أداة CI. Bitrise و Jenkins لديهما خطوات جاهزة لـ XCTest.

تغطية الكود هي ميزة مدمجة في XCTest تُظهر أي أسطر الكود مغطاة بالاختبارات. يعرض Xcode التغطية باللون الأخضر (مغطى) والأحمر (غير مغطى) والأصفر (مغطى جزئيًا). الحد الأدنى لتغطية كود الإنتاج هو 70% للمنطق التجاري الحرج. وفقًا لـ Google Testing Blog (2024)، فرض تغطية 80% لجميع الوحدات يؤدي إلى «اختبارات فارغة» لا تتحقق من المنطق بل تنفذ الكود فقط.

الأسئلة الشائعة

كيف يختلف XCTest عن Quick و Nimble؟

XCTest هو إطار العمل الرسمي من Apple مع تكامل مباشر في Xcode. Quick و Nimble هما مكتبتان خارجيتان توفران بناء جملة BDD وتأكيدات أكثر قابلية للقراءة. Quick و Nimble مناسبان لاختبارات القبول، لكن XCTest أكثر موثوقية لاختبارات الوحدة بسبب عدم وجود تبعيات خارجية.

كيفية اختبار الكود غير المتزامن في XCTest؟

يتم اختبار الكود غير المتزامن عبر XCTestExpectation + `wait(for:timeout:)` أو عبر طرق `async/await` في XCTest (iOS 13+). لواجهات برمجة التطبيقات القائمة على callback، يتم إنشاء توقع يتم استيفاؤه في الإغلاق. لـ async/await، تُستخدم التأكيدات القياسية في الدوال غير المتزامنة.

كيفية محاكاة التبعيات في XCTest؟

لا يحتوي XCTest على إطار عمل مدمج للمحاكاة. يتم تنفيذ المحاكاة من خلال البروتوكولات: يتم إنشاء فئة محاكاة تطبق نفس البروتوكول مثل التبعية الحقيقية. للتوليد التلقائي للمحاكيات، تُستخدم Cuckoo أو SwiftyMocky أو المحاكيات اليدوية. حقن التبعية عبر المُهيئات هو شرط إلزامي لقابلية الاختبار.

هل يمكن تشغيل XCTest على أجهزة حقيقية؟

نعم، يتم تشغيل XCTest على أجهزة حقيقية عبر Xcode أو xcodebuild مع المعامل `-destination 'platform=iOS,name=iPhone 15'`. اختبارات واجهة المستخدم على الأجهزة الحقيقية تعطي نتائج أكثر دقة من المحاكيات. للتشغيل على مزارع الأجهزة، تُستخدم BrowserStack أو Sauce Labs أو Firebase Test Lab.

ما الجديد في Swift Testing مقارنة بـ XCTest؟

Swift Testing (2024) هو إطار عمل جديد من Apple مع الماكرو `@Test` و `@Suite` و `@Expect`. يوفر معلمات اختبار مدمجة وتجميع في مجموعات وبناء جملة أكثر قابلية للقراءة. يتعايش Swift Testing مع XCTest ولا يحل محله. يظل XCTest إطار العمل الرئيسي لاختبارات واجهة المستخدم واختبارات الأداء.

الخلاصة

  • XCTest — إطار العمل الرسمي للاختبارات من Apple، مدمج في Xcode ويدعم Swift و Objective-C.
  • XCTestCase يوفر دورة حياة setUp/tearDown ومجموعة من التأكيدات لاختبارات الوحدة.
  • XCTestExpectation و XCTWaiter هما آليتان لاختبار الكود غير المتزامن مع callbacks و async/await.
  • اختبارات الأداء تستخدم measure(metrics:) مع دعم XCTClockMetric و XCTMemoryMetric و XCTCPUMetric.
  • التأكيدات — XCTAssertEqual و XCTAssertTrue و XCTAssertNil و XCTAssertThrowsError و XCTUnwrap وغيرها.
  • تكامل CI/CD عبر xcodebuild و Xcode Cloud و GitHub Actions مع إنشاء تقارير تلقائية.
  • Swift Testing — إطار عمل جديد من Apple يكمل XCTest لاختبارات الوحدة والمعلمات.

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا