بدء استخدام اختبارات Game Loop

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

استنادًا إلى محرّك اللعبة، يمكنك تنفيذ اختبارات باستخدام ملف واحد أو عدة ملفات حلقات. الحلقة هي عبارة عن جولة كاملة أو جزئية من الاختبار على تطبيق الألعاب. يمكن استخدام حلقات الألعاب لإجراء ما يلي:

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

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

قبل البدء

لتنفيذ اختبار، عليك أولاً ضبط إعدادات تطبيقك لإجراء اختبارات Game Loop.

  1. في ملف بيان تطبيقك، أضِف فلتر أهداف جديدًا إلى نشاطك:

    <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، يمكنك إنشاء اختبار على الفور وتشغيله في تطبيق الألعاب. يمكنك اختيار إجراء اختبار في Test Lab باستخدام وحدة تحكّمFirebase أو واجهة سطر الأوامر (CLI) في gcloud، أو على جهاز محلي باستخدام "مدير اختبارات الالتفاف".

التشغيل على جهاز محلي

Test Loop Manager من Test Lab هو تطبيق مفتوح المصدر يساعدك في دمج اختبارات حلقة الألعاب وتشغيلها على أجهزتك المحلية. ويسمح ذلك أيضًا لفريق ضمان الجودة بتشغيل حلقات اللعب نفسها على أجهزتهم.

لإجراء اختبار على جهاز محلي باستخدام "مدير حلقة الاختبار":

  1. نزِّل Test Loop Manager على هاتف أو جهاز لوحي وثبِّته من خلال تشغيل:
    adb install testloopmanager.apk
  2. على جهازك، افتح تطبيق Test Loop Apps على هاتفك أو جهازك اللوحي. يعرض التطبيق قائمة بالتطبيقات على جهازك التي يمكن تشغيلها باستخدام حلقات الألعاب. إذا لم يظهر تطبيق الألعاب هنا، تأكَّد من أنّ فلتر الأهداف يتطابق مع الفلتر الموضّح في الخطوة الأولى من القسم "قبل البدء".
  3. اختَر تطبيق الألعاب، ثم اختَر عدد مرات التكرار التي تريد تنفيذها. ملاحظة: في هذه الخطوة، يمكنك اختيار تنفيذ مجموعة فرعية من الحلقات بدلاً من برمجة دورة واحدة فقط. لمزيد من المعلومات حول تشغيل عدة حلقات في آنٍ واحد، اطّلِع على الميزات الاختيارية.
  4. انقر على إجراء الاختبار. يبدأ اختبارك على الفور.

التشغيل في Test Lab

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

استخدام وحدة تحكّم Firebase

  1. في وحدة تحكّم Firebase، انقر على Test Lab من اللوحة اليمنى.
  2. انقر على إجراء الاختبار الأول (أو إجراء اختبار إذا سبق أن أجرى مشروعك اختبارًا).
  3. اختَر حلقة اللعب كنوع الاختبار، ثم انقر على متابعة.
  4. انقر على تصفّح، ثم تصفّح للوصول إلى ملف .apk الخاص بتطبيقك. ملاحظة: في هذه الخطوة، يمكنك اختيار تنفيذ مجموعة فرعية من الحلقات بدلاً من برمجة دورة واحدة فقط. لمزيد من المعلومات حول تشغيل عدة حلقات في آنٍ واحد، اطّلِع على الميزات الاختيارية.
  5. انقر على متابعة.
  6. اختَر الأجهزة الفعلية التي تريد استخدامها لاختبار تطبيقك.
  7. انقر على بدء الاختبارات.

لمزيد من المعلومات عن بدء استخدام وحدة تحكّم Firebase، يُرجى الاطّلاع على مقالة بدء الاختبار باستخدام وحدة تحكّم Firebase.

استخدام سطر أوامر gcloud

  1. نزِّل Google Cloud SDK وثبِّته إذا لم يسبق لك ذلك.

  2. سجِّل الدخول إلى gcloud CLI باستخدام حسابك على 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
    

لمزيد من المعلومات عن بدء استخدام gcloud CLI، يُرجى الاطّلاع على بدء الاختبار من سطر أوامر gcloud.

الميزات الاختيارية

يوفّر Test Lab العديد من الميزات الاختيارية التي تتيح لك تخصيص اختباراتك بشكل أكبر، بما في ذلك إمكانية كتابة بيانات الإخراج ودعم Loops متعددة للألعاب وLabels للLoops ذات الصلة.

كتابة بيانات الإخراج

يمكن لاختبار حلقة الألعاب كتابة الإخراج في ملف محدّد في أسلوب launchIntent.getData(). بعد إجراء اختبار، يمكنك الوصول إلى بيانات الإخراج هذه في قسم Test Lab ضمن وحدة تحكّم Firebase (اطّلِع على مثال على ملف إخراج اختبار حلقة الألعاب).

يتّبع تطبيق Test Lab أفضل الممارسات لمشاركة ملف بين التطبيقات الموضّحة في مقالة مشاركة ملف. في طريقة 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. في تطبيق "مدير حلقة الاختبار"، تظهر شاشة اختيار تسمح لك باختيار الحلقات التي تريد تشغيلها. إذا اخترت عدة دورات، يتم تشغيل كل دورة تسلسليًا بعد اكتمال الدورة السابقة.

  • إذا كنت تُجري اختبارًا باستخدام وحدة تحكّم Firebase، أدخِل قائمة أو نطاقًا من أرقام الحلقات في حقل السيناريوهات.

  • إذا كنت بصدد إجراء اختبار باستخدام واجهة سطر أوامر 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.

تصنيف حلقات الألعاب

عند تصنيف حلقات اللعب باستخدام تصنيف سيناريو واحد أو أكثر، يمكنك أنت وفريق فحص الجودة إطلاق مجموعة من حلقات اللعب ذات الصلة بسهولة (مثل "all compatibility game loops") واختبارها في مصفوفة واحدة. يمكنك إنشاء تصنيفاتك الخاصة أو استخدام التصنيفات المحدّدة مسبقًا التي يوفّرها Test Lab:

  • com.google.test.loops.player_experience: حلقات For المستخدَمة لإعادة تمثيل تجربة مستخدم حقيقي عند تشغيل اللعبة إنّ الهدف من الاختبار باستخدام هذه الحلقات هو العثور على المشاكل التي سيواجهها مستخدم حقيقي أثناء لعب اللعبة.
  • com.google.test.loops.gpu_compatibility: دوائر For الحلقية المستخدَمة لاختبار المشاكل المتعلّقة بوحدة معالجة الرسومات يهدف الاختبار باستخدام هذه الحلقات إلى تنفيذ تعليمات برمجية لوحدة معالجة الرسومات قد لا تعمل بشكل صحيح في مرحلة الإنتاج، وذلك لرصد المشاكل المتعلّقة بالأجهزة وبرامج التشغيل.
  • com.google.test.loops.compatibility: دوائر For الحلقية المستخدَمة لاختبار مجموعة واسعة من مشاكل التوافق، بما في ذلك مشاكل I/O وOpenSSL
  • com.google.test.loops.performance: دوائر For المستخدَمة لاختبار أداء الجهاز على سبيل المثال، قد يتم تشغيل لعبة باستخدام إعدادات الرسومات الأكثر تعقيدًا لتحديد أداء جهاز جديد.

لتفعيل تطبيقك لتشغيل الحلقات باستخدام التصنيف نفسه:

  • إذا كنت بصدد إجراء اختبار باستخدام "مدير حلقة الاختبار":

    1. في بيان تطبيقك، أضِف سطر البيانات الوصفية التالي واستبدِل LABEL_NAME بتصنيف من اختيارك:

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

      في الحقل android:value، يمكنك تحديد نطاق أو مجموعة من الأعداد الصحيحة من 1 إلى 1024 (الحد الأقصى لعدد الحلقات المسموح به لاختبار واحد) التي representتمثل الحلقات التي تريد تصنيفها. يُرجى العِلم أنّه يتم فهرسة الحلقات بدءًا من 1 وليس 0. على سبيل المثال، يطبّق android:value="1,3-5" LABEL_NAME على الحلقات 1 و3 و4 و5.

    2. في تطبيق "أداة إدارة حلقة الاختبار"، أدخِل تصنيفًا واحدًا أو أكثر في حقل التصنيفات.

  • إذا كنت تُجري اختبارًا باستخدام وحدة تحكّم Firebase، أدخِل علامة واحدة أو أكثر في حقل العلامات.

  • إذا كنت تُجري اختبارًا باستخدام gcloud CLI، حدِّد علامة سيناريو واحدة أو أكثر باستخدام العلامة --scenario-labels (مثل --scenario-labels=performance,gpu).

دعم ترخيص التطبيقات

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

المشكلات المعروفة

تواجه اختبارات Game Loop في Test Lab المشاكل المعروفة التالية:

  • لا تتيح بعض الأعطال تتبُّع تسلسل استدعاء الدوال البرمجية. على سبيل المثال، قد تؤدي بعض إصدارات الإصدار إلى تجاهُل ناتج عملية debuggerd باستخدام prctl(PR_SET_DUMPABLE, 0). لمزيد من المعلومات، يُرجى الاطّلاع على debuggerd.
  • لا يتوفّر حاليًا المستوى 19 من واجهة برمجة التطبيقات بسبب أخطاء في أذونات الملفات.