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

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

لإجراء اختبار على جهاز محلّي باستخدام Test Loop Manager:

  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. نزِّل حزمة تطوير البرامج (SDK) لخدمة Google Cloud وثبِّتها، إذا لم يسبق لك إجراء ذلك.

  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 متعددة للألعاب وعلامات للحلقات ذات الصلة.

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

يمكن لاختبار حلقة الألعاب كتابة الإخراج في ملف محدّد في أسلوب 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، يمكنك تشغيل ملف برمجي دوار لللعبة مباشرةً لإعادة إنتاج العُطل واختبار الإصلاحات.

لتفعيل تطبيقك لتشغيل عدة حلقات في آنٍ واحد:

  • في حال إجراء اختبار باستخدام Test Loop Manager:

    1. أضِف السطر التالي إلى بيان تطبيقك، داخل العنصر <application>:

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

      يحتوي هدف الإطلاق هذا على حلقة الاستهداف كمَعلمة عددية. في الحقل android:value، يمكنك تحديد عدد صحيح من 1 إلى 1024 (الحد الأقصى لعدد التكرارات المسموح بها لاختبار واحد). لاحظ أن التكرارات الحلقية تتم فهرستها بدءًا من 1 وليس 0.

    2. في تطبيق "مدير حلقة الاختبار"، تظهر شاشة اختيار تسمح لك باختيار الحلقات التي تريد تشغيلها. إذا حددت حلقات متعددة، فسيتم تشغيل كل حلقة بالتسلسل بعد اكتمال التكرار الحلقي السابق.

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

  • في حال إجراء اختبار باستخدام gcloud CLI، حدِّد قائمة بأرقام حلقة التكرار باستخدام العلامة --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: التكرارات الحلقية التي تُستخدم لإعادة تقديم تجربة المستخدم الحقيقية عند تشغيل اللعبة. إنّ الهدف من الاختبار باستخدام هذه الحلقات هو العثور على المشاكل التي قد يواجهها مستخدم حقيقي أثناء لعب اللعبة.
  • com.google.test.loops.gpu_compatibility: دوائر For الحلقية المستخدَمة لاختبار المشاكل المتعلّقة بوحدة معالجة الرسومات يهدف الاختبار باستخدام هذه الحلقات إلى تنفيذ تعليمات برمجية لوحدة معالجة الرسومات قد لا تعمل بشكل صحيح في مرحلة الإنتاج، وذلك لرصد المشاكل المتعلّقة بالأجهزة وبرامج التشغيل.
  • com.google.test.loops.compatibility: بالنسبة إلى التكرارات الحلقية المستخدمة لاختبار مجموعة كبيرة من مشاكل التوافق، بما في ذلك مشاكل وحدات الإدخال والإخراج ومشاكل OpenSSL.
  • com.google.test.loops.performance: للحلقات المستخدمة لاختبار أداء الجهاز. على سبيل المثال، قد يتم تشغيل لعبة باستخدام إعدادات الرسومات الأكثر تعقيدًا لرصد أداء جهاز جديد.

لتمكين تطبيقك من تشغيل تكرارات تحمل التصنيف نفسه، عليك اتّباع الخطوات التالية:

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

    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.

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

تتضمّن اختبارات حلقة الألعاب في Test Lab المشاكل المعروفة التالية:

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