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

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

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

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

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

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

כדי להטמיע בדיקה, קודם צריך להגדיר את האפליקציה לבדיקות של 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 והפעלתה

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

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

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

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

  1. מורידים את Test Loop Manager לטלפון או לטאבלט ומתקינים אותו באמצעות הפקודה:
    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.

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

  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 (ראו דוגמה לקובץ פלט של בדיקת Game Loop).

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
}

מספר game loops

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

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

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

    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: לולאות For שמשמשות לשחזור החוויה של משתמש אמיתי במהלך המשחק. מטרת הבדיקה באמצעות הלולאות האלה היא למצוא בעיות שמשתמשים אמיתיים עשויים להיתקל בהן במהלך המשחק.
  • com.google.test.loops.gpu_compatibility: לולאות For שמשמשות לבדיקת בעיות שקשורות ל-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 יש את הבעיות הידועות הבאות:

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