איך מתחילים לעבוד עם בדיקות של לולאת משחקים

יכול להיות שיהיה קשה להפוך את בדיקת המשחקים לאוטומטית כשאפליקציות המשחקים מבוססות על מסגרות UI שונות. בדיקות לולאת משחקים מאפשרות לשלב את הבדיקות המקוריות עם Test Lab ולהריץ אותן בקלות במכשירים נבחרים. בבדיקה של Game Loop, הבדיקה מתבצעת באפליקציית המשחק תוך סימולציה של הפעולות של שחקן אמיתי. במדריך הזה מוסבר איך להריץ בדיקת Game Loop, ואז להציג ולנהל את תוצאות הבדיקה במסוף Firebase.

בהתאם למנוע המשחק, תוכלו להטמיע בדיקות עם לולאה אחת או יותר. לולאה היא הרצה מלאה או חלקית של הבדיקה באפליקציית המשחקים. אפשר להשתמש בלופ של משחקים כדי:

  • הפעלת שלב במשחק באותו אופן שבו משתמש קצה יכול לשחק בו. אפשר לכתוב סקריפט של הקלט של המשתמש, לאפשר למשתמש להיות במצב חוסר פעילות או להחליף את המשתמש ב-AI אם זה הגיוני במשחק (לדוגמה, אם יש לכם אפליקציית משחק מכוניות מרוץ שכבר הטמעתם בה AI. תוכלו להעביר בקלות מנהל התקן AI שאחראי על הקלט של המשתמש).
  • כדאי להריץ את המשחק בהגדרת האיכות הגבוהה ביותר כדי לבדוק אם המכשירים תומכים בה.
  • מריצים בדיקה טכנית (הרכבת מספר תוכנות הצללה, הפעלה שלהם, בדיקה שהפלט פועל כמצופה וכו').

אפשר להריץ בדיקת Game Loop במכשיר בדיקה אחד, בקבוצת מכשירי בדיקה או ב-Test Lab. עם זאת, לא מומלץ להריץ בדיקות של Game Loop במכשירים וירטואליים, כי שיעור הפריימים של הגרפיקה שלהם נמוך יותר מאשר במכשירים פיזיים.

לפני שמתחילים

כדי להטמיע בדיקה, קודם צריך להגדיר את האפליקציה לבדיקות לולאת משחקים.

  1. במניפסט של האפליקציה, מוסיפים מסנן Intent חדש לפעילות:

    <activity android:name=".MyActivity">
       <intent-filter>
           <action android:name="com.google.intent.action.TEST_LOOP"/>
           <category android:name="android.intent.category.DEFAULT"/>
           <data android:mimeType="application/javascript"/>
       </intent-filter>
       <intent-filter>
          ... (other intent filters here)
       </intent-filter>
    </activity>
    

    כך תוכלו להפעיל את המשחק דרך Test Lab באמצעות כוונה ספציפית.

  2. בקוד (מומלץ להוסיף את הקוד הזה בתוך ההצהרה על השיטה onCreate), מוסיפים את הקוד הבא:

    Kotlin+KTX

    val launchIntent = intent
    if (launchIntent.action == "com.google.intent.action.TEST_LOOP") {
        val scenario = launchIntent.getIntExtra("scenario", 0)
        // Code to handle your game loop here
    }

    Java

    Intent launchIntent = getIntent();
    if(launchIntent.getAction().equals("com.google.intent.action.TEST_LOOP")) {
        int scenario = launchIntent.getIntExtra("scenario", 0);
        // Code to handle your game loop here
    }

    כך הפעילות תוכל לבדוק את הכוונה שהפעילה אותה. אם אתם מעדיפים, תוכלו להוסיף את הקוד הזה מאוחר יותר (למשל, אחרי הטעינה הראשונית של מנוע המשחק).

  3. מומלץ: בסוף הבדיקה, מוסיפים:

    Kotlin+KTX

    yourActivity.finish()

    Java

    yourActivity.finish();

    הפקודה הזו תסגור את האפליקציה בסיום הבדיקה של Game Loop. הבדיקה מסתמכת על מסגרת ממשק המשתמש של האפליקציה כדי להתחיל את הלולאה הבאה, ועצירתה של האפליקציה מסמנת לה שהבדיקה הסתיימה.

יצירה והפעלה של בדיקה ללולאת משחקים

אחרי שמגדירים את האפליקציה לבדיקות של Game Loop, אפשר ליצור בדיקה מיד ולהריץ אותה באפליקציית המשחקים. אפשר להריץ בדיקה ב-Test Lab באמצעות מסוף Firebase או ממשק שורת הפקודה (CLI) של gcloud, או במכשיר מקומי באמצעות Test Loop Manager.

הפעלה במכשיר מקומי

Test Loop Manager של Test Lab היא אפליקציה בקוד פתוח שבעזרתה אפשר לשלב בדיקות של Game Loop ולהריץ אותן במכשירים המקומיים. היא גם מאפשרת לצוות הבטחת האיכות להריץ את אותם לולאות משחק במכשירים שלהם.

כדי להריץ בדיקה במכשיר מקומי באמצעות Test Loop Manager:

  1. מורידים את מנהל לולאת הבדיקה בטלפון או בטאבלט, ומתקינים אותו על ידי הרצת:
    adb install testloopmanager.apk
  2. פותחים את האפליקציה Test Loop Apps בטלפון או בטאבלט. באפליקציה מוצגת רשימת האפליקציות במכשיר שאפשר להריץ באמצעות לולאות משחק. אם אפליקציית המשחקים לא מופיעה כאן, צריך לוודא שמסנן הכוונה תואם למסנן שמתואר בשלב הראשון בקטע לפני שמתחילים.
  3. בוחרים את אפליקציית המשחקים ואז בוחרים את מספר הלולאות שרוצים להריץ. הערה: בשלב הזה, אפשר להריץ קבוצת משנה של לולאות במקום רק לולאה אחת. מידע נוסף על הפעלת כמה לולאות בו-זמנית זמין בקטע תכונות אופציונליות.
  4. לוחצים על הפעלת הבדיקה. הבדיקה תתחיל לפעול באופן מיידי.

הפעלה בTest Lab

אפשר להריץ בדיקת Game Loop ב-Test Lab באמצעות מסוף Firebase או CLI של gcloud. לפני שמתחילים, אם עדיין לא עשיתם זאת, פותחים את מסוף Firebase ויוצרים פרויקט.

שימוש במסוף Firebase

  1. במסוף Firebase, לוחצים על Test Lab בחלונית הימנית.
  2. לוחצים על Run Your First Test (או על Run a Test אם כבר הרצתם בדיקה בפרויקט).
  3. בוחרים באפשרות Game Loop (מחזור משחק) בתור סוג הבדיקה ולוחצים על Continue (המשך).
  4. לוחצים על Browse (עיון) ועוברים לקובץ .apk של האפליקציה. הערה: בשלב הזה תוכלו להפעיל קבוצת משנה של לולאות במקום רק לולאה אחת. מידע נוסף על הפעלת כמה לולאות בו-זמנית זמין בקטע תכונות אופציונליות.
  5. לוחצים על המשך.
  6. בוחרים את המכשירים הפיזיים שבהם רוצים לבדוק את האפליקציה.
  7. לוחצים על התחלת הבדיקות.

מידע נוסף על תחילת העבודה עם מסוף Firebase זמין במאמר תחילת הבדיקה באמצעות מסוף Firebase.

שימוש בשורת הפקודה של gcloud (CLI)

  1. אם עדיין לא עשיתם זאת, מורידים ומתקינים את Google Cloud SDK

  2. נכנסים ל-CLI של gcloud באמצעות חשבון Google:

    gcloud auth login

  3. מגדירים את פרויקט Firebase ב-gcloud, כאשר PROJECT_ID הוא המזהה של פרויקט Firebase:

    gcloud config set project PROJECT_ID
    
  4. הריצו את הבדיקה הראשונה:

    gcloud firebase test android run \
     --type=game-loop --app=<var>path-to-apk</var> \
     --device model=herolte,version=23
    

למידע נוסף על תחילת העבודה עם ה-CLI של gcloud, ראו תחילת הבדיקה משורת הפקודה של gcloud.

תכונות אופציונליות

ב-Test Lab יש כמה תכונות אופציונליות שמאפשרות להתאים אישית את הבדיקות עוד יותר, כולל היכולת לכתוב נתוני פלט, תמיכה במספר לולאות משחק ותוויות ללולאות קשורות.

כתיבת נתוני פלט

בדיקת Game Loop יכולה לכתוב פלט לקובץ שצוין ב-method‏ launchIntent.getData(). אחרי שמריצים בדיקה, אפשר לגשת לנתוני הפלט האלה בקטע Test Lab במסוף Firebase (דוגמה לקובץ פלט בבדיקה של לולאת משחקים).

Test Lab פועלת לפי השיטות המומלצות לשיתוף קבצים בין אפליקציות, כפי שמתואר בקטע שיתוף קובץ. כדי לבדוק את קובץ הפלט של הנתונים, מריצים את הקוד הבא ב-method‏ onCreate() של הפעילות, שבו נמצאת הכוונה:

Kotlin+KTX

val launchIntent = intent
val logFile = launchIntent.data
logFile?.let {
    Log.i(TAG, "Log file ${it.encodedPath}")
    // ...
}

Java

Intent launchIntent = getIntent();
Uri logFile = launchIntent.getData();
if (logFile != null) {
    Log.i(TAG, "Log file " + logFile.getEncodedPath());
    // ...
}

אם רוצים לכתוב בקובץ מצד ה-C++ של אפליקציית המשחק, אפשר להעביר את מתאר הקובץ במקום את נתיב הקובץ:

Kotlin+KTX

val launchIntent = intent
val logFile = launchIntent.data
var fd = -1
logFile?.let {
    Log.i(TAG, "Log file ${it.encodedPath}")
    fd = try {
        contentResolver
            .openAssetFileDescriptor(logFile, "w")!!
            .parcelFileDescriptor
            .fd
    } catch (e: FileNotFoundException) {
        e.printStackTrace()
        -1
    } catch (e: NullPointerException) {
        e.printStackTrace()
        -1
    }
}

// C++ code invoked here.
// native_function(fd);

Java

Intent launchIntent = getIntent();
Uri logFile = launchIntent.getData();
int fd = -1;
if (logFile != null) {
    Log.i(TAG, "Log file " + logFile.getEncodedPath());
    try {
        fd = getContentResolver()
                .openAssetFileDescriptor(logFile, "w")
                .getParcelFileDescriptor()
                .getFd();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
        fd = -1;
    } catch (NullPointerException e) {
        e.printStackTrace();
        fd = -1;
    }
}

// C++ code invoked here.
// native_function(fd);

C++‎

#include <unistd.h>
JNIEXPORT void JNICALL
Java_my_package_name_MyActivity_native_function(JNIEnv *env, jclass type, jint log_file_descriptor) {
// The file descriptor needs to be duplicated.
int my_file_descriptor = dup(log_file_descriptor);
}

דוגמה לקובץ פלט

אתם יכולים להשתמש בקובצי נתוני פלט (בפורמט של הדוגמה הבאה) כדי להציג תוצאות של בדיקת לולאת משחק בקטע Test Lab במסוף Firebase. אזורים שמוצגים כ-/.../ יכולים להכיל כל שדה מותאם אישית שדרוש לכם, כל עוד השמות שלהם לא מתנגשים עם השמות של שדות אחרים שמשמשים בקובץ הזה:

{
  "name": "test name",
  "start_timestamp": 0, // Timestamp of the test start (in us).
                           Can be absolute or relative
  "driver_info": "...",
  "frame_stats": [
    {
      "timestamp": 1200000, // Timestamp at which this section was written
                               It contains value regarding the period
                               start_timestamp(0) -> this timestamp (1200000 us)
      "avg_frame_time": 15320, // Average time to render a frame in ns
      "nb_swap": 52, // Number of frame rendered
      "threads": [
        {
          "name": "physics",
          "Avg_time": 8030 // Average time spent in this thread per frame in us
        },
        {
          "name": "AI",
          "Avg_time": 2030 // Average time spent in this thread per frame in us
        }
      ],
      /.../ // Any custom field you want (vertices display on the screen, nb units …)
    },
    {
      // Next frame data here, same format as above
    }
  ],
  "loading_stats": [
    {
      "name": "assets_level_1",
      "total_time": 7850, // in us
      /.../
    },
    {
      "name": "victory_screen",
      "total_time": 554, // in us
      /.../
    }

  ],
  /.../, // You can add custom fields here
}

כמה מחזורי משחק

יכול להיות שיהיה שימושי להריץ כמה לולאות משחק באפליקציה. לולאה היא ריצה מלאה של אפליקציית המשחק מתחילתה ועד סופה. לדוגמה, אם יש במשחק כמה רמות, מומלץ להשתמש בלולאה אחת של משחק כדי להפעיל כל רמה במקום בלולאה אחת שמבצעת איטרציה בכל הרמות. כך, אם האפליקציה קורסת ברמה 32, אפשר להפעיל את לולאה של המשחק ישירות כדי לשחזר את הקריסה ולבדוק תיקוני באגים.

כדי לאפשר לאפליקציה להריץ כמה לולאות בו-זמנית:

  • אם אתם מריצים בדיקה באמצעות מנהל לולאת הבדיקה:

    1. מוסיפים את השורה הבאה למניפסט של האפליקציה, בתוך הרכיב <application>:

      <meta-data
        android:name="com.google.test.loops"
        android:value="5" />
      

      כוונת ההפעלה הזו מכילה את לולאת היעד כפרמטר של מספר שלם. בשדה android:value אפשר לציין מספר שלם מ-1 עד 1024 (מספר הלולאות המקסימלי שמותר לבדיקה אחת). חשוב לזכור שהאינדקס של הלולאות מתחיל ב-1 ולא ב-0.

    2. באפליקציית Test Loop Manager מופיע מסך בחירה שמאפשר לבחור את הלולאות שרוצים להריץ. אם בוחרים כמה לולאות, כל לולאה מופעלת ברצף אחרי שהלולאה הקודמת מסתיימת.

  • אם מריצים בדיקה באמצעות מסוף Firebase, צריך להזין רשימה או טווח של מספרי לולאה בשדה Scenarios.

  • אם מריצים בדיקה באמצעות ה-CLI של gcloud, מציינים רשימה של מספרי לולאות באמצעות הדגל --scenario-numbers. לדוגמה, --scenario-numbers=1,3,5 מפעיל את לולאות 1, 3 ו-5.

  • אם אתם כותבים ב-C++ ואתם רוצים לשנות את ההתנהגות של הלולאה, עליכם להעביר את הפרמטר הנוסף הבא לקוד ה-C++ המקורי:

    Kotlin+KTX

    val launchIntent = intent
    val scenario = launchIntent.getIntExtra("scenario", 0)

    Java

    Intent launchIntent = getIntent();
    int scenario = launchIntent.getIntExtra("scenario", 0);

    עכשיו אפשר לשנות את ההתנהגות של הלולאה על סמך הערך של int שנוצר.

מתן תוויות ל-game loops

כשאתם מסמנים את מחזורי המשחק בתוויות של תרחיש אחד או יותר, אתם וצוות בקרת האיכות יכולים להפעיל בקלות קבוצה של מחזורי משחק קשורים (למשל, "כל לולאות המשחקים התואמות") ולבדוק אותן במטריצה אחת. אתם יכולים ליצור תוויות משלכם או להשתמש בתוויות המוגדרות מראש שמוצעות על ידי Test Lab:

  • com.google.test.loops.player_experience: ללולאות שמשמשות לשחזור החוויה של משתמש אמיתי בזמן המשחק. מטרת הבדיקה באמצעות הלולאות האלה היא למצוא בעיות שמשתמשים אמיתיים עשויים להיתקל בהן במהלך המשחק.
  • com.google.test.loops.gpu_compatibility: ללולאות שמשמשות לבדיקת בעיות שקשורות ל-GPU. מטרת הבדיקה באמצעות הלולאות האלה היא להריץ קוד GPU שייתכן שלא יפעל כראוי בסביבת הייצור, כדי לחשוף בעיות בחומרה ובמנהלי התקנים.
  • com.google.test.loops.compatibility: לולאות For שמשמשות לבדיקת מגוון רחב של בעיות תאימות, כולל בעיות קלט/פלט ובעיות ב-OpenSSL.
  • com.google.test.loops.performance: לולאות For שמשמשות לבדיקת הביצועים של המכשיר. לדוגמה, יכול להיות שמשחק יפעל בהגדרות הגרפיקה המורכבות ביותר כדי לראות איך מכשיר חדש מתנהג.

כדי לאפשר לאפליקציה להריץ לולאות עם אותה תווית:

  • אם אתם מריצים בדיקה באמצעות Test Loop Manager:

    1. במניפסט של האפליקציה, מוסיפים את שורת המטא-נתונים הבאה ומחליפים את LABEL_NAME בתווית לבחירתכם:

      <meta-data
       android:name="com.google.test.loops.LABEL_NAME"
       android:value="1,3-5" />
      

      בשדה android:value, אפשר לציין טווח או קבוצה של מספרים שלמים מ-1 עד 1024 (המספר המקסימלי של לולאות שמותר לבדיקה אחת) שמייצגים את הלולאות שרוצים לתייג. חשוב לדעת שהאינדקס של הלולאות מתחיל ב-1 ולא ב-0. לדוגמה, android:value="1,3-5" מחילה את LABEL_NAME על הלולאות 1, 3, 4 ו-5.

    2. באפליקציית Test Loop Manager, מזינים תווית אחת או יותר בשדה Labels.

  • אם אתם מפעילים בדיקה באמצעות מסוף Firebase, מזינים תווית אחת או יותר בשדה Labels.

  • אם מריצים בדיקה באמצעות ה-CLI של gcloud, מציינים תווית אחת או יותר של תרחיש באמצעות הדגל --scenario-labels (למשל, --scenario-labels=performance,gpu).

תמיכה ברישוי אפליקציות

Test Lab תומך באפליקציות שמשתמשות בשירות רישוי אפליקציות ש-Google Play מציעה. כדי לבדוק את הרישוי בזמן בדיקת האפליקציה באמצעות Test Lab, צריך לפרסם את האפליקציה בערוץ הייצור בחנות Play. כדי לבדוק את האפליקציה בערוץ אלפא או בטא באמצעות Test Lab, צריך להסיר את בדיקת הרישוי לפני העלאת האפליקציה אל Test Lab.

בעיות מוכרות

בבדיקות של Game Loop ב-Test Lab יש את הבעיות הידועות הבאות:

  • בחלק מהקריסות אין תמיכה במעקב לאחור. לדוגמה, בחלק מהגרסאות ה-build של גרסאות הפצה יכול להיות שהפלט של התהליך debuggerd יושתק באמצעות prctl(PR_SET_DUMPABLE, 0). מידע נוסף זמין במאמר debuggerd.
  • נכון לעכשיו אין תמיכה ברמת API 19 בגלל שגיאות בהרשאות הקבצים.