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

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

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

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

يمكنك إجراء اختبار "حلقة الألعاب" على جهاز اختباري واحد أو مجموعة من الأجهزة الاختبارية أو على Test Lab. ومع ذلك، لا ننصح بإجراء اختبارات 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)، أضِف ما يلي:

    KotlinJava
    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
    }
    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. يُفضّل إضافة ما يلي في نهاية الاختبار:

    KotlinJava
    yourActivity.finish()
    yourActivity.finish();

    يؤدي ذلك إلى إغلاق تطبيقك عند اكتمال اختبار "حلقة الألعاب". يعتمد الاختبار على إطار عمل واجهة المستخدم لتطبيقك من أجل بدء التكرار التالي، ويؤدي إغلاق تطبيقك إلى إعلام إطار العمل بأنّ الاختبار قد انتهى.

إنشاء اختبار "حلقة الألعاب" وتشغيله

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

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

Test LabTest 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. اختَر Game Loop كنوع الاختبار، ثم انقر على متابعة.
  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 العديد من الميزات الاختيارية التي تتيح لك تخصيص اختباراتك بشكل أكبر، بما في ذلك إمكانية كتابة بيانات الإخراج، وتوفير الدعم لحلقات لعب متعددة، وتصنيفات للحلقات ذات الصلة.

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

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

تتّبع Test Lab أفضل الممارسات لمشاركة ملف بين التطبيقات الموضّحة في مشاركة ملف. في طريقة onCreate() الخاصة بنشاطك، حيث يقع هدفك، يمكنك التحقّق من ملف إخراج البيانات من خلال تشغيل الرمز التالي:

KotlinJava
val launchIntent = intent
val logFile = launchIntent.data
logFile?.let {
    Log.i(TAG, "Log file ${it.encodedPath}")
    // ...
}
Intent launchIntent = getIntent();
Uri logFile = launchIntent.getData();
if (logFile != null) {
    Log.i(TAG, "Log file " + logFile.getEncodedPath());
    // ...
}

إذا أردت الكتابة في الملف من جهة C++ في تطبيق لعبتك، يمكنك تمرير واصف الملف بدلاً من مسار الملف:

KotlinJavaC++‎
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);
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);
#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 CLI، حدِّد قائمة بأرقام التكرار باستخدام العلامة --scenario-numbers. على سبيل المثال، --scenario-numbers=1,3,5 يشغّل الحلقات 1 و3 و5.

  • إذا كنت تكتب رمز C++ وأردت تغيير سلوك الحلقة، مرِّر الإضافة التالية إلى رمز C++ الأصلي:

    KotlinJava
    val launchIntent = intent
    val scenario = launchIntent.getIntExtra("scenario", 0)
    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: حلقات التكرار المستخدَمة لاختبار المشاكل المتعلّقة بوحدة معالجة الرسومات والهدف من الاختبار باستخدام هذه الحلقات هو تنفيذ رمز وحدة معالجة الرسومات الذي قد لا يعمل بشكل صحيح في مرحلة الإنتاج، وذلك للكشف عن المشاكل المتعلقة بالأجهزة وبرامج التشغيل.
  • com.google.test.loops.compatibility: حلقات التكرار المستخدَمة لاختبار مجموعة كبيرة من مشاكل التوافق، بما في ذلك مشاكل الإدخال/الإخراج ومشاكل 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 (الحد الأقصى لعدد التكرارات المسموح به لاختبار واحد) التي تمثّل التكرارات التي تريد تصنيفها. يُرجى العِلم أنّه يتم فهرسة الحلقات بدءًا من 1 وليس 0. على سبيل المثال، ينطبق android:value="1,3-5" على الحلقات 1 و3 و4 و5.LABEL_NAME

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

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

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

إتاحة ترخيص التطبيقات

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

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

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

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