بدء استخدام اختبارات حلقة الألعاب لأجهزة iOS

باستخدام اختبارات "حلقة الألعاب"، يمكنك كتابة اختبارات أصلية لمحرك لعبتك ثم تشغيلها في Test Lab على الأجهزة التي تختارها. بهذه الطريقة، لن تحتاج إلى القلق بشأن الكتابة لواجهات مستخدم أو أُطر عمل اختبار مختلفة. يحاكي اختبار حلقة الألعاب إجراءات لاعب حقيقي، وعند تشغيله على Test Lab، يوفّر طريقة سريعة وقابلة للتوسّع للتحقّق من أنّ لعبتك تعمل بشكل جيد للمستخدمين.

توضّح لك هذه الصفحة كيفية إجراء اختبار حلقة الألعاب، ثم عرض نتائج الاختبار وإدارتها في صفحة Test Lab ضمن وحدة تحكّم Firebase. يمكنك أيضًا تخصيص اختباراتك بشكل أكبر باستخدام ميزات اختيارية، مثل كتابة نتائج اختبار مخصّصة أو إنهاء الاختبار مبكرًا.

ما هو اختبار حلقة الألعاب؟

الحلقة هي تشغيل كامل أو جزئي للاختبار على لعبة على الأجهزة الجوّالة. يمكنك إجراء اختبار حلقة الألعاب محليًا على محاكي أو على مجموعة من الأجهزة في Test Lab. يمكن استخدام اختبارات "حلقة الألعاب" لإجراء ما يلي:

  • شغِّل لعبتك كما لو كنت مستخدمًا نهائيًا. يمكنك إما كتابة نص برمجي لإدخال المستخدم، أو ترك المستخدم في وضع عدم النشاط، أو استبدال المستخدم بذكاء اصطناعي (على سبيل المثال، إذا قمت بتطبيق الذكاء الاصطناعي في لعبة سباق سيارات، يمكنك وضع سائق ذكاء اصطناعي مسؤولاً عن إدخال المستخدم).

  • شغِّل لعبتك بأعلى إعدادات الجودة لمعرفة الأجهزة التي يمكنها تشغيلها.

  • إجراء اختبار فني، مثل تجميع عدة برامج تظليل وتنفيذها والتحقّق من أنّ النتيجة مطابقة للتوقعات

الخطوة 1: تسجيل مخطّط عنوان URL المخصّص لـ "Test Lab"

أولاً، عليك تسجيل مخطّط URL مخصّص لـ Firebase Test Lab في تطبيقك:

  1. في Xcode، اختَر هدفًا للمشروع.

  2. انقر على علامة التبويب معلومات، ثم أضِف نوع عنوان URL جديدًا.

  3. في حقل مخطّطات عناوين URL، أدخِل firebase-game-loop. يمكنك أيضًا تسجيل مخطّط URL مخصّص من خلال إضافته إلى ملف إعداد Info.plist الخاص بمشروعك في أي مكان ضمن علامة <dict>:

    <key>CFBundleURLTypes</key>
     <array>
         <dict>
             <key>CFBundleURLName</key>
             <string></string>
             <key>CFBundleTypeRole</key>
             <string>Editor</string>
             <key>CFBundleURLSchemes</key>
             <array>
                 <string>firebase-game-loop</string>
             </array>
         </dict>
     </array>
    

تم الآن ضبط تطبيقك لإجراء اختبار باستخدام Test Lab.

الخطوة 2 (اختيارية): ضبط تطبيقك لتشغيل تكرارات متعددة

إذا كان تطبيقك يحتوي على عدة مخطّطات URL مخصّصة مسجّلة وكنت تخطّط لتشغيل عدة تكرارات حلقية (تُعرف أيضًا باسم السيناريوهات) في الاختبار، يجب تحديد التكرارات الحلقية التي تريد تشغيلها في تطبيقك في وقت الإطلاق.

في مفوَّض تطبيقك، يمكنك إلغاء طريقة application(_:open:options:):

Swift

func application(_app: UIApplication,
                 open url: URL
                 options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    let components = URLComponents(url: url, resolvingAgainstBaseURL: true)!
    if components.scheme == "firebase-game-loop" {
        // ...Enter Game Loop Test logic to override application(_:open:options:).
    }
    return true
}

Objective-C

- (BOOL)application:(UIApplication *)app
            openURL:(NSURL *)url
            options:(NSDictionary &lt;UIApplicationOpenURLOptionsKey, id&gt; *)options {
  if ([url.scheme isEqualToString:(@"firebase-game-loop")]) {
      // ...Enter Game Loop Test logic to override application(_:open:options:).
  }
}

عند تشغيل عدة تكرارات حلقية في الاختبار، يتم تمرير التكرار الحلقي الحالي كمَعلمة إلى عنوان URL المستخدَم لتشغيل التطبيق. يمكنك أيضًا الحصول على رقم التكرار الحلقي الحالي من خلال تحليل عنصر URLComponents المستخدَم لجلب مخطّط URL مخصّص:

Swift

if components.scheme == "firebase-game-loop" {
    // Iterate over all parameters and find the one with the key "scenario".
    let scenarioNum = Int(components.queryItems!.first(where: { $0.name == "scenario" })!.value!)!
    // ...Write logic specific to the current loop (scenarioNum).
}

Objective-C

if ([url.scheme isEqualToString:(@"firebase-game-loop")]) {
    // Launch the app as part of a game loop.
    NSURLComponents *components = [NSURLComponents componentsWithURL:url
                                             resolvingAgainstBaseURL:YES];
    for (NSURLQueryItem *item in [components queryItems]) {
        if ([item.name isEqualToString:@"scenario"]) {
            NSInteger scenarioNum = [item.value integerValue];
            // ...Write logic specific to the current loop (scenarioNum).
        }
    }
}

الخطوة 3: إنشاء اختبار وتنفيذه

بعد تسجيل مخطّط URL المخصّص لـ "Test Lab"، يمكنك إجراء الاختبار في وحدة تحكّم Firebase أو باستخدام gcloud beta CLI. إذا لم يسبق لك إنشاء ملف IPA لتطبيقك، يمكنك إنشاؤه الآن (ستحتاج إلى تحديد موقعه لاحقًا).

إجراء اختبار في وحدة تحكّم Firebase

  1. في وحدة تحكّم Firebase، انتقِل إلى DevOps والتفاعل > Test Lab.

  2. انقر على إجراء الاختبار الأول > تشغيل حلقة ألعاب iOS.

  3. في قسم تحميل التطبيق، انقر على تصفُّح، ثم اختَر ملف IPA الخاص بتطبيقك (إذا لم يسبق لك ذلك، أنشئ ملف IPA لتطبيقك).

  4. (اختياري) إذا أردت تشغيل تكرارات متعددة (تُعرف أيضًا باسم السيناريوهات) في وقت واحد أو اختيار تكرارات معيّنة لتشغيلها، أدخِل أرقام التكرارات في حقل السيناريوهات.

    على سبيل المثال، عند إدخال 1-3, 5، يشغّل Test Lab الحلقات 1 و2 و3 و5. وفقًا للإعدادات التلقائية (إذا لم تُدخل أي بيانات في حقل السيناريوهات)، لن يشغّل Test Lab سوى التكرار 1.

  5. في قسم الأجهزة، اختَر جهازًا فعليًا واحدًا أو أكثر تريد اختبار تطبيقك عليه، ثم انقر على بدء الاختبارات.

إجراء اختبار باستخدام gcloud beta CLI

  1. إذا لم يسبق لك ذلك، اضبط بيئة حزمة تطوير البرامج (SDK) المحلية لـ gcloud، ثم تأكَّد من تثبيت مكوّن gcloud التجريبي.

  2. شغِّل الأمر gcloud beta firebase test ios run واستخدِم العلامات التالية لضبط عملية التشغيل:

علامات اختبارات "حلقة الألعاب"
--type

مطلوب: يحدِّد نوع اختبار iOS الذي تريد إجراؤه. يمكنك إدخال نوعَي الاختبار xctest (تلقائي) أو game-loop.

--app

مطلوب: المسار المطلق (Google Cloud Storage أو نظام الملفات) إلى ملف IPA الخاص بتطبيقك. لا تكون هذه العلامة صالحة إلا عند إجراء اختبارات حلقة الألعاب.

--scenario-numbers

الحلقات (المعروفة أيضًا باسم السيناريوهات) التي تريد تشغيلها في تطبيقك. يمكنك إدخال حلقة واحدة أو قائمة أو حلقات أو نطاق من الحلقات. القيمة التلقائية للتكرار هي 1.

على سبيل المثال، يشغّل --scenario-numbers=1-3,5 الحلقات 1 و2 و3 و5.

--device-model

الجهاز الفعلي الذي تريد إجراء الاختبار عليه (يمكنك الاطّلاع على الأجهزة المتاحة التي يمكنك استخدامها).

--timeout

الحدّ الأقصى لمدة الاختبار يمكنك إدخال عدد صحيح لتمثيل المدة بالثواني، أو عدد صحيح وتعداد لتمثيل المدة كوحدة زمنية أطول.

على سبيل المثال:

  • يفرض --timeout=200 إنهاء الاختبار عند تشغيله لمدة تصل إلى 200 ثانية.
  • يفرض --timeout=1h إنهاء الاختبار عندما يستمر لمدة تصل إلى ساعة.

على سبيل المثال، يشغّل الأمر التالي اختبار حلقة الألعاب الذي ينفّذ الحلقات 1 و4 و6 و7 و8 على هاتف iPhone 8 Plus:

gcloud beta firebase test ios run
 --type game-loop --app path/to/my/App.ipa --scenario-numbers 1,4,6-8
 --device-model=iphone8plus

لمزيد من المعلومات حول gcloud CLI، يُرجى الاطّلاع على المستندات المرجعية.

إجراء اختبار محليًا

لإجراء الاختبار على جهازك، حمِّل تطبيق الألعاب في محاكي وشغِّل:

xcrun simctl openurl SIMULATOR_UDID firebase-game-loop://
  • يمكنك العثور على معرّف UDID الخاص بالمحاكي من خلال تشغيل الأمر instruments -s devices.

  • إذا كان هناك محاكي واحد فقط قيد التشغيل، أدخِل السلسلة الخاصة "booted" بدلاً من SIMULATOR_UDID.

إذا كان الاختبار يحتوي على تكرارات متعددة، يمكنك تحديد التكرار الذي تريد تشغيله من خلال تمرير رقم التكرار إلى العلامة scenario. يُرجى العِلم أنّه يمكنك تشغيل تكرار واحد فقط في كل مرة عند إجراء الاختبار على جهازك. على سبيل المثال، إذا أردت تشغيل التكرارات الحلقية 1 و2 و5، يجب تشغيل أمر منفصل لكل تكرار حلقي:

xcrun simctl openurl SIMULATOR_UDID firebase-game-loop://?scenario=1
xcrun simctl openurl SIMULATOR_UDID firebase-game-loop://?scenario=2
xcrun simctl openurl SIMULATOR_UDID firebase-game-loop://?scenario=5

إنهاء اختبار قبل موعده

يستمر اختبار حلقة الألعاب تلقائيًا إلى أن تنتهي مهلة الخمس دقائق، حتى بعد تنفيذ جميع الحلقات. عند الوصول إلى المهلة، ينتهي الاختبار ويلغي أي حلقات معلقة. يمكنك تسريع الاختبار أو إنهاؤه مبكرًا من خلال استدعاء مخطّط عنوان URL المخصّص Test Lab firebase-game-loop-complete في AppDelegate لتطبيقك. على سبيل المثال:

Swift

/// End the loop by calling our custom url scheme.
func finishLoop() {
    let url = URL(string: "firebase-game-loop-complete://")!
    UIApplication.shared.open(url)
}

Objective-C

- (void)finishLoop {
  UIApplication *app = [UIApplication sharedApplication];
  [app openURL:[NSURL URLWithString:@"firebase-game-loop-complete://"]
      options:@{}
completionHandler:^(BOOL success) {}];
}

يُنهي اختبار "حلقة الألعاب" الحلقة الحالية وينفّذ الحلقة التالية. عندما لا يكون هناك المزيد من التكرارات لتشغيلها، ينتهي الاختبار.

كتابة نتائج اختبار مخصّصة

يمكنك ضبط اختبار "حلقة الألعاب" لكتابة نتائج اختبار مخصّصة في نظام ملفات جهازك. بهذه الطريقة، عندما يبدأ الاختبار، يخزّن Test Lab ملفات النتائج في دليل GameLoopsResults على جهاز الاختبار (الذي يجب إنشاؤه بنفسك). عند انتهاء الاختبار، تنقل أداة Test Lab جميع الملفات من دليل GameLoopResults إلى حزمة مشروعك. يُرجى مراعاة ما يلي عند إعداد الاختبار:

  • يتم تحميل جميع ملفات النتائج بغض النظر عن نوع الملف أو حجمه أو كميته.

  • لا يعالج Test Lab نتائج الاختبار حتى تنتهي جميع الحلقات في الاختبار من العمل، لذلك إذا كان الاختبار يتضمن حلقات متعددة تكتب المخرجات، فتأكد من إلحاقها بملف نتيجة فريد أو إنشاء ملف نتيجة لكل حلقة. بهذه الطريقة، يمكنك تجنب الكتابة فوق النتائج من حلقة سابقة.

لإعداد الاختبار لكتابة نتائج اختبار مخصّصة:

  1. في دليل تطبيقك Documents، أنشئ دليلاً باسم GameLoopResults.

  2. من أي مكان في رمز تطبيقك (على سبيل المثال، مفوّض تطبيقك)، أضِف ما يلي:

    Swift

    /// Write to a results file.
    func writeResults() {
      let text = "Greetings from game loops!"
      let fileName = "results.txt"
      let fileManager = FileManager.default
      do {
    
      let docs = try fileManager.url(for: .documentDirectory,
                                     in: .userDomainMask,
                                     appropriateFor: nil,
                                     create: true)
      let resultsDir = docs.appendingPathComponent("GameLoopResults")
      try fileManager.createDirectory(
          at: resultsDir,
          withIntermediateDirectories: true,
          attributes: nil)
      let fileURL = resultsDir.appendingPathComponent(fileName)
      try text.write(to: fileURL, atomically: false, encoding: .utf8)
      } catch {
        // ...Handle error writing to file.
      }
    }
    

    Objective-C

    /// Write to a results file.
    - (void)writeResults:(NSString *)message {
        // Locate and create the results directory (if it doesn't exist already).
        NSFileManager *manager = [NSFileManager defaultManager];
        NSURL* url = [[manager URLsForDirectory:NSDocumentDirectory
                                      inDomains:NSUserDomainMask] lastObject];
        NSURL* resultsDir = [url URLByAppendingPathComponent:@"GameLoopResults"
                                                 isDirectory:YES];
        [manager createDirectoryAtURL:resultsDir
          withIntermediateDirectories:NO
                           attributes:nil
                                error:nil];
    
        // Write the result message to a text file.
        NSURL* resultFile = [resultsDir URLByAppendingPathComponent:@"result.txt"];
        if ([manager fileExistsAtPath:[resultFile path]]) {
            // Append to the existing file
            NSFileHandle *handle = [NSFileHandle fileHandleForWritingToURL:resultFile
                                                                     error:nil];
            [handle seekToEndOfFile];
            [handle writeData:[message dataUsingEncoding:NSUTF8StringEncoding]];
            [handle closeFile];
        } else {
            // Create and write to the file.
            [message writeToURL:resultFile
                     atomically:NO
                       encoding:NSUTF8StringEncoding error:nil];
        }
    }