ابدأ مع اختبارات Game Loop

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

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

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

يمكنك إجراء اختبار Game Loop على جهاز اختبار واحد، أو مجموعة من أجهزة الاختبار، أو على 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. يعتمد الاختبار على إطار عمل واجهة المستخدم لتطبيقك لبدء الحلقة التالية، ويخبره إغلاق تطبيقك بانتهاء الاختبار.

إنشاء وتشغيل اختبار Game Loop

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

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

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

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

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

تشغيل في مختبر الاختبار

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

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

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

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

استخدم سطر أوامر gcloud (CLI)

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

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

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

يتبع 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);

سي ++

#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. في تطبيق Test Loop Manager، تظهر شاشة تحديد تتيح لك تحديد الحلقة (الحلقات) التي تريد تشغيلها. إذا قمت بتحديد حلقات متعددة، فسيتم تشغيل كل حلقة بالتسلسل بعد اكتمال الحلقة السابقة.

  • إذا كنت تجري اختبارًا باستخدام وحدة تحكم 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 الناتجة.

حلقات اللعبة التسمية

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

  • com.google.test.loops.player_experience : للحلقات المستخدمة لإعادة إنتاج تجربة المستخدم الحقيقية عند لعب اللعبة. الهدف من الاختبار باستخدام هذه الحلقات هو العثور على المشكلات التي قد يواجهها المستخدم الحقيقي أثناء لعب اللعبة.
  • com.google.test.loops.gpu_compatibility : للحلقات المستخدمة لاختبار المشكلات المتعلقة بوحدة معالجة الرسومات. الهدف من الاختبار باستخدام هذه الحلقات هو تنفيذ تعليمات برمجية 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، أدخل تسمية واحدة أو أكثر في حقل التسميات .

  • إذا كنت تجري اختبارًا باستخدام وحدة تحكم 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 .
  • مستوى API 19 غير مدعوم حاليًا بسبب أخطاء في أذونات الملف.