شروع کار با آزمایش‌های «حلقه بازی» برای iOS

با آزمایش‌های «حلقه بازی»، می‌توانید آزمایش‌های بومی موتور بازی‌تان را بنویسید و سپس آن‌ها را در Test Lab در دستگاه‌هایی که انتخاب می‌کنید اجرا کنید. به‌این‌ترتیب، لازم نیست نگران نوشتن برای چارچوب‌های آزمایشی یا میانای کاربر مختلف باشید. آزمون «حلقه بازی» کنش‌های بازیکن واقعی را شبیه‌سازی می‌کند و وقتی آن را در Test Lab اجرا می‌کنید، روشی سریع و مقیاس‌پذیر برای تأیید عملکرد خوب بازی‌تان برای کاربران ارائه می‌دهد.

این صفحه به شما نشان می‌دهد که چگونه یک آزمایش Game Loop را اجرا کنید، سپس نتایج آزمایش خود را در صفحه Test Lab کنسول Firebase مشاهده و مدیریت کنید. همچنین می‌توانید با ویژگی‌های اختیاری، مثل نوشتن نتایج آزمایش سفارشی یا پایان دادن زودهنگام به آزمایش، آزمایش‌هایتان را بیشتر سفارشی‌سازی کنید.

«آزمون حلقه بازی» چیست؟

حلقه اجرای کامل یا جزئی آزمایش شما در برنامه بازی شما است. می‌توانید آزمایش «حلقه بازی» را به‌صورت محلی در شبیه‌ساز یا در مجموعه‌ای از دستگاه‌ها در Test Lab اجرا کنید. از آزمایش‌های Game Loop می‌توان برای موارد زیر استفاده کرد:

  • بازی‌تان را همان‌طور که کاربر نهایی بازی می‌کند اجرا کنید. می‌توانید ورودی کاربر را اسکریپت کنید، کاربر را در حالت غیرفعال قرار دهید، یا کاربر را با هوش مصنوعی جایگزین کنید (برای مثال، اگر هوش مصنوعی را در بازی مسابقه اتومبیل‌رانی پیاده‌سازی کرده‌اید، می‌توانید راننده هوش مصنوعی را مسئول ورودی کاربر قرار دهید).

  • بازی‌تان را با بالاترین تنظیم کیفیت اجرا کنید تا ببینید کدام دستگاه‌ها می‌توانند از آن پشتیبانی کنند.

  • آزمایشی فنی اجرا کنید، مثلاً چند سایه‌زن را کامپایل کنید، آن‌ها را اجرا کنید، و بررسی کنید که برونداد مطابق انتظار باشد.

مرحله ۱: ثبت کردن طرح‌واره نشانی وب سفارشی Test Lab

ابتدا باید طرح‌واره نشانی وب سفارشی Firebase Test Lab را در برنامه‌تان ثبت کنید:

  1. در Xcode، هدف پروژه را انتخاب کنید.

  2. روی برگه اطلاعات کلیک کنید، سپس نوع نشانی وب جدیدی اضافه کنید.

  3. در فیلد طرح‌واره‌های نشانی وب، firebase-game-loop را وارد کنید. همچنین می‌توانید طرح‌واره نشانی وب سفارشی را با افزودن آن به فایل پیکربندی 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 پیکربندی شده است.

مرحله ۲ (اختیاری): پیکربندی برنامه برای اجرای چند حلقه

اگر برنامه‌تان چند طرح‌واره نشانی وب سفارشی ثبت‌شده دارد و قصد دارید چند حلقه (یا سناریو) را در آزمایشتان اجرا کنید، باید مشخص کنید که می‌خواهید کدام حلقه‌ها در زمان راه‌اندازی در برنامه‌تان اجرا شوند.

در نماینده برنامه‌تان، روش 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:).
  }
}

وقتی چندین حلقه را در آزمایشتان اجرا می‌کنید، حلقه فعلی به‌عنوان پارامتر به نشانی وب مورداستفاده برای راه‌اندازی برنامه ارسال می‌شود. همچنین می‌توانید با تجزیه کردن شیء URLComponents مورداستفاده برای واکشی طرح‌واره نشانی وب سفارشی، شماره حلقه فعلی را دریافت کنید:

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).
        }
    }
}

مرحله ۳: ایجاد و اجرای آزمایش

پس‌از ثبت طرح‌واره نشانی وب سفارشی 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

حلقه‌هایی (یا سناریوهایی) که می‌خواهید در برنامه‌تان اجرا شود. می‌توانید یک حلقه، فهرستی از حلقه‌ها، یا دامنه‌ای از حلقه‌ها را وارد کنید. حلقه پیش‌فرض ۱ است.

برای مثال، --scenario-numbers=1-3,5 حلقه‌های ۱، ۲، ۳، و ۵ را اجرا می‌کند.

--device-model

دستگاه فیزیکی‌ای که می‌خواهید آزمایشتان را در آن اجرا کنید (ببینید از کدام دستگاه‌های دردسترس می‌توانید استفاده کنید).

--timeout

حداکثر مدت زمانی که می‌خواهید آزمایشتان اجرا شود. می‌توانید عدد صحیحی را برای نشان دادن مدت به ثانیه وارد کنید، یا عدد صحیح و شمارشی را برای نشان دادن مدت به‌عنوان واحد زمانی طولانی‌تر وارد کنید.

برای مثال:

  • --timeout=200 آزمایش شما را مجبور می‌کند وقتی تا ۲۰۰ ثانیه اجرا شد، خاتمه یابد.
  • --timeout=1h آزمایشتان را مجبور می‌کند وقتی تا یک ساعت اجرا می‌شود، خاتمه یابد.

برای مثال، فرمان زیر یک آزمایش «حلقه بازی» را اجرا می‌کند که حلقه‌های ۱، ۴، ۶، ۷، و ۸ را در 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، به اسناد مرجع مراجعه کنید.

اجرای آزمایش به‌صورت محلی

برای اجرای آزمایش به‌صورت محلی، برنامه بازی‌تان را در شبیه‌ساز بار کنید و این دستور را اجرا کنید:

xcrun simctl openurl SIMULATOR_UDID firebase-game-loop://
  • می‌توانید UDID شبیه‌سازتان را با اجرای فرمان instruments -s devices پیدا کنید.

  • اگر فقط یک شبیه‌ساز درحال اجرا است، رشته ویژه "booted" را به‌جای SIMULATOR_UDID وارد کنید.

اگر آزمایشتان حاوی چند حلقه است، می‌توانید با ارسال شماره حلقه به پرچم scenario، مشخص کنید کدام حلقه اجرا شود. توجه داشته باشید که هنگام اجرای محلی آزمایش، فقط می‌توانید یک حلقه را در هر زمان اجرا کنید. برای مثال، اگر می‌خواهید حلقه‌های ۱، ۲، و ۵ را اجرا کنید، باید برای هر حلقه فرمان جداگانه‌ای اجرا کنید:

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

پایان دادن زودهنگام به آزمایش

به‌طور پیش‌فرض، آزمایش «حلقه بازی» تا زمانی که به زمان اتمام پنج دقیقه‌ای برسد، به اجرا ادامه می‌دهد، حتی اگر همه حلقه‌ها اجرا شده باشند. وقتی زمان استراحت به‌پایان می‌رسد، آزمایش تمام می‌شود و هرگونه حلقه معلق لغو می‌شود. می‌توانید با فراخوانی طرح‌واره نشانی وب سفارشی 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];
        }
    }