اختبار E2E لتطبيقات Swift: من XCUITest إلى حالات واقعية

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

لماذا تعتبر اختبارات E2E "وضع الإله" لمطور iOS؟

\n\n

تخيل: لقد كتبت كود Swift مثاليًا، كل شيء يتم تجميعه، واختبارات الوحدة خضراء. تقوم بإصدار الإصدار - وبعد ساعة تظهر الأخطاء: زر "شراء" لا يعمل على iPhone 14 Pro، وشاشة الدخول على iPad Mini تبدو كلوحة تجريدية. هل هذا مألوف؟ هنا يأتي دور اختبار E2E لتطبيقات Swift - الطريقة الوحيدة للتأكد من أن تطبيقك يعمل كالساعة في أيدي مستخدم حقيقي.

\n\n

تحاكي اختبارات End-to-End (E2E) السيناريو الكامل للمستخدم: من تشغيل التطبيق إلى إكمال الإجراء المستهدف (شراء، تسجيل، إرسال نموذج). في هذه المقالة، سنشرح كيفية إعداد XCUITest Swift بحيث لا تفشل اختباراتك لأسباب تافهة، ولا يتحول خط أنابيب CI/CD إلى جحيم.

\n\n

ما الذي ستتعلمه:

\n
    \n
  • كيفية كتابة اختبارات UI مستقرة باستخدام XCUITest
  • \n
  • نموذج Page Object لـ Swift - مثال عملي
  • \n
  • معالجة العمليات غير المتزامنة والانتظارات
  • \n
  • دمج اختبارات E2E في CI/CD (GitHub Actions + Fastlane)
  • \n
  • أهم 3 أخطاء للمبتدئين وكيفية تجنبها
  • \n
\n\n

الأدوات: ما سنحتاجه

\n\n

لـ أتمتة اختبار Swift سنستخدم ثلاث ركائز:

\n
    \n
  1. XCUITest - إطار عمل من Apple، مدمج في XCTest. يسمح بمحاكاة الإيماءات والتحقق من حالات عناصر UI.
  2. \n
  3. Xcode Test Plan - لتكوين مخططات الاختبار (لغات مختلفة، اتجاهات، بيانات).
  4. \n
  5. Fastlane + GitHub Actions - لتشغيل الاختبارات على CI.
  6. \n
\n\n

بناء جملة XCUITest الأساسي بسيط: يمكنك الوصول إلى التطبيق عبر XCUIApplication()، والبحث عن العناصر عبر buttons["Login"] أو textFields["email"] ومحاكاة الإجراءات.

\n\n

كتابة أول اختبار E2E: سيناريو تسجيل الدخول

\n\n

لنفترض أن لدينا شاشة دخول تحتوي على حقلي البريد الإلكتروني وكلمة المرور وزر "تسجيل الدخول". الهدف: التحقق من أنه عند إدخال بيانات صحيحة، ينتقل المستخدم إلى الشاشة الرئيسية.

\n\n
import XCTest\n\nclass LoginE2ETests: XCTestCase {\n    \n    let app = XCUIApplication()\n    \n    override func setUpWithError() throws {\n        continueAfterFailure = false\n        app.launch()\n    }\n    \n    func testSuccessfulLogin() throws {\n        // 1. نجد العناصر\n        let emailField = app.textFields["emailTextField"]\n        let passwordField = app.secureTextFields["passwordTextField"]\n        let loginButton = app.buttons["signInButton"]\n        \n        // 2. إجراءات المستخدم\n        emailField.tap()\n        emailField.typeText("user@example.com")\n        \n        passwordField.tap()\n        passwordField.typeText("ValidPassword123")\n        \n        loginButton.tap()\n        \n        // 3. نتحقق من النتيجة\n        let dashboard = app.staticTexts["dashboardTitle"]\n        XCTAssertTrue(dashboard.waitForExistence(timeout: 5))\n    }\n}
\n\n

نقطة مهمة: استخدم waitForExistence(timeout:) - بدون ذلك قد يفشل الاختبار إذا تأخرت الرسوم المتحركة أو طلب الشبكة. هذا هو أساس اختبار E2E لتطبيقات Swift.

\n\n

لماذا قد يفشل هذا الكود؟

\n
    \n
  • قد لا يكون حقل الإدخال هو المستجيب الأول - أضف .tap() قبل typeText.
  • \n
  • قد يكون الزر مغطى بلوحة المفاتيح - استخدم app.keyboards.buttons["Return"].tap().
  • \n
  • قد تختلف تسميات النصوص حسب الترجمة - استخدم دائمًا معرف Accessibility Identifier.
  • \n
\n\n

نموذج Page Object (POM) لـ Swift: جعل الاختبارات نظيفة

\n\n

عندما يكبر التطبيق، تتحول الاختبارات إلى فوضى. الحل هو نموذج Page Object. نقوم بإنشاء فئات منفصلة لكل شاشة، تغلف منطق البحث عن العناصر والإجراءات.

\n\n

مثال لشاشة تسجيل الدخول:

\n\n
// Lo                

المدونات

توصيات الكتب