Ir a la consola

Prueba de bucle de juego de Firebase Test Lab

La automatización de las pruebas de juegos es un desafío debido a la amplia gama de marcos de trabajo de IU que se utilizan para el desarrollo de juegos (algunos de los cuales son dependientes del motor) y debido a las dificultades para automatizar la navegación de la IU en ellos. Para admitir las pruebas en apps de juegos, Test Lab incluye ahora compatibilidad con un “modo de demostración” en el que se ejecuta la app de juego mientras se simulan las acciones de un jugador. Este modo puede incluir múltiples bucles (o situaciones), que pueden organizarse lógicamente mediante etiquetas para que puedas ejecutar bucles relacionados al mismo tiempo.

En este documento se proporcionan lineamientos para implementar bucles de juego de modo que puedas utilizarlos fácilmente para probar el juego en la etapa de desarrollo. Estos lineamientos se aplican si las pruebas se ejecutan en un solo dispositivo de prueba, en una granja de dispositivos de prueba o con Test Lab.

Cómo comenzar

Para usar la prueba de bucle de juego en Test Lab, el juego debe modificarse para hacer lo siguiente:

  1. Iniciar el bucle
  2. Ejecutar el bucle
  3. Cerrar la app de juego (opcional)

Inicia el bucle

Cuando se inicia la prueba de bucle, se activa el juego con un intent específico, por lo que debes modificar el manifiesto y agregar un nuevo filtro de intents a la actividad, como se muestra en el siguiente ejemplo de código:

<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>

Ejecuta el bucle

Cuando se inicie la actividad, comprueba qué intent la inició, como se muestra en el siguiente ejemplo de código:

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
}

Kotlin

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
}

Recomendamos ejecutar este código en el método onCreate, pero puedes ejecutarlo más tarde si lo prefieres (por ejemplo, después de cargar inicialmente el motor del juego). A continuación, puedes implementar el bucle de juego (o varios bucles, como se describe en Varios bucles de juego) como desees, según el motor del juego. A modo de ejemplo, los bucles de juego pueden usarse para lo siguiente:

  • Ejecutar un nivel del juego de la misma manera en la que lo usaría un usuario final. Puedes escribir la entrada del usuario, dejar que el usuario esté inactivo o reemplazarlo con una inteligencia artificial si el juego lo permite (por ejemplo, si ya tienes implementada una IA, como en un juego de carreras, puedes poner fácilmente un conductor de IA en el rol del usuario).
  • Ejecutar el juego con la configuración de calidad más alta para comprobar la compatibilidad con los dispositivos.
  • Ejecutar una prueba técnica (compilar varios shaders, ejecutarlos, comprobar que el resultado sea el esperado, etcétera).

Test Loop Manager

Para ayudarte a integrar los bucles de juego y ejecutarlos en tus dispositivos locales, así como para ayudar a tu equipo de Control de calidad a ejecutar bucles de juego en sus dispositivos, proporcionamos una aplicación de código abierto llamada Test Loop Manager.

Para utilizar Test Loop Manager, sigue estos pasos:

  1. Descarga Test Loop Manager.
  2. Instala Test Loop Manager en el dispositivo, con el siguiente comando:
    adb install testloopmanager.apk
  3. Abre la app (llamada "Test Loop Apps") en el teléfono o la tablet. Verás una lista de apps que contienen bucles de juego. Si no ves aquí la app, comprueba que el filtro de intents coincida con el que se describe en Inicia el bucle.
  4. Selecciona la app del juego que desees probar.
    1. Después de hacer clic en el nombre de la app de juego en la lista, selecciona las situaciones (es decir, los bucles de juego) que implementará la app. Si la app implementa varios bucles, consulta Varios bucles de juego.
    2. Haz clic en Run Test y observa cómo se ejecutan las situaciones.

Cierra la app de juego

Al final de la prueba, debes cerrar la app con:

Java

yourActivity.finish();

Kotlin

yourActivity.finish()

Generalmente, la prueba de bucle de juego permite que el marco de trabajo de la IU inicie el siguiente bucle. Si no cierras la app, el marco de trabajo de la IU que ejecuta los bucles no sabrá que terminó la prueba y finalizará la app después de un tiempo.

Ejecuta la prueba de bucle de juego en Test Lab

Ve a Firebase console y crea un proyecto si aún no lo has hecho. Para utilizar Test Lab sin costo, pero con una cuota diaria limitada, usa el plan de facturación Spark. Si quieres obtener más información para usar Test Lab sin límites, consulta los planes de precios de Firebase.

Usa Firebase console

Utiliza las siguientes instrucciones para ejecutar una prueba de bucle de juego con Firebase console:

  1. En Firebase console, haz clic en Test Lab en el panel de navegación izquierdo.
  2. Haz clic en Ejecutar la primera prueba (o Ejecutar una prueba, si el proyecto ya ejecutó alguna prueba anteriormente).
  3. Selecciona el tipo de prueba Bucle de juego y luego haz clic en Continuar.
  4. Haz clic en Explorar y, luego, selecciona el archivo .apk de la app.
  5. (Opcional) Para seleccionar un subconjunto de situaciones disponibles (bucles de juego), realiza una de las siguientes acciones:

    • Si quieres elegir situaciones específicas, ingresa una lista o un rango de números de situaciones en el campo Situaciones.
    • Si quieres elegir todas las situaciones que tengan una etiqueta específica, ingresa una o más etiquetas de situación en el campo Etiquetas.
  6. Haz clic en Continuar.

  7. Selecciona los dispositivos físicos que se utilizarán para probar la app.

  8. Haz clic en Iniciar pruebas.

Para obtener más información sobre Firebase Console, consulta cómo usar Firebase Test Lab desde Firebase console.

Usa el entorno de la línea de comandos de gcloud

Utiliza las siguientes instrucciones para ejecutar una prueba de bucle de juego mediante el entorno de línea de comandos (CLI) de gcloud:

  1. Si aún no tienes un proyecto de Firebase, ve a Firebase console y haz clic en Agregar proyecto para crear uno.
  2. Instala el SDK de Google Cloud, que incluye la CLI de gcloud.
  3. Accede con una Cuenta de Google:

    gcloud auth login

  4. Configura el proyecto de Firebase con el siguiente comando, en el que PROJECT_ID es el proyecto de Firebase que creaste en el paso 1:

    gcloud config set project PROJECT_ID
    
  5. Ejecuta la primera prueba, de la siguiente manera:

    gcloud firebase test android run \
    --type=game-loop --app=<path-to-apk> \
    --device model=herolte,version=23
  6. (Opcional) Para seleccionar un subconjunto de situaciones disponibles (bucles de juego), realiza una de las siguientes acciones cuando ejecutes una prueba de bucle de juego:

    • Si quieres elegir situaciones específicas, indica una lista de números de situaciones con la marca --scenario-numbers (por ejemplo, --scenario-numbers=1,3,5).
    • Si quieres elegir todas las situaciones que tengan una etiqueta específica, indica una o más etiquetas de situación con la marca --scenario-labels (por ejemplo, --scenario-labels=performance,gpu).

Para obtener más información sobre el uso de la CLI de gcloud con Test Lab, consulta cómo usar Firebase Test Lab for Android desde la línea de comandos de gcloud.

Características opcionales

En esta sección se describe cómo usar las características opcionales, como escribir datos en un archivo de salida, compatibilidad con varios bucles de juego y etiquetar bucles relacionados, de manera que puedas probar fácilmente bucles relacionados en una sola matriz de prueba.

Escribe datos de salida

El bucle de juego puede escribir la salida en un archivo proporcionado con el método launchIntent.getData(). Test Lab puede mostrar estos datos de salida en la página de resultados de la prueba. Para ver un ejemplo de un archivo de salida de datos, consulta el ejemplo de archivo de salida de una prueba de bucle de juego.

Test Lab sigue las recomendaciones descritas en Cómo compartir un archivo para compartir un archivo con otra app. En el método onCreate() de tu actividad, donde obtienes el intent, también puedes buscar ese archivo mediante el siguiente código:

Java

Intent launchIntent = getIntent();
Uri logFile = launchIntent.getData();
if (logFile != null) {
    Log.i(TAG, "Log file " + logFile.getEncodedPath());
    // ...
}

Kotlin

val launchIntent = intent
val logFile = launchIntent.data
logFile?.let {
    Log.i(TAG, "Log file ${it.encodedPath}")
    // ...
}

Si deseas escribir en ese archivo desde el lado de C++ de la app de juego, tendrías que pasar el descriptor del archivo, en lugar de la ruta del archivo, como se muestra en el siguiente ejemplo de código:

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);

Kotlin

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);

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);
}

Varios bucles de juego

También puedes tener compatibilidad con varios bucles de juego en la app. Por ejemplo, si tu juego incluye varios niveles, es conveniente que tengas un bucle de juego para iniciar cada nivel, en lugar de tener un bucle que se repita en todos ellos.

De esta forma, si falla la app en el nivel 32, puedes iniciar directamente ese bucle de juego para intentar reproducir la falla y probar correcciones de errores.

Por ejemplo, si tienes 5 bucles de juego en la app, solo necesitas agregar una línea al archivo de manifiesto de tu app, dentro del elemento <application>:

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

A continuación, cuando inicies Test Loop Manager, podrás utilizar una pantalla de selección para elegir qué bucle iniciar. Si seleccionas que se inicien varios bucles, cada uno se iniciará en secuencia una vez completado el anterior. Con Test Lab, tú seleccionas qué bucles iniciar.

El intent de inicio contiene el bucle de destino como un parámetro de número entero, en el rango de 1 al número máximo de bucles admitidos.

Puedes leer el extra del intent en Java, como se muestra en el siguiente ejemplo de código:

Java

Intent launchIntent = getIntent();
int scenario = launchIntent.getIntExtra("scenario", 0);

Kotlin

val launchIntent = intent
val scenario = launchIntent.getIntExtra("scenario", 0)

A continuación, puedes pasar este extra al código nativo C++ para cambiar el comportamiento del bucle sobre la base del valor int resultante.

Etiqueta los bucles de juego

Puedes etiquetar el bucle de juego con una o más etiquetas de situación para facilitar al equipo de Control de calidad el inicio de un conjunto de bucles de juego relacionados (por ejemplo, "todos los bucles de juego de compatibilidad"). Para ello, debes agregar una línea de metadatos al archivo de manifiesto de la app, similar al siguiente ejemplo:

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

Puedes crear tus propias etiquetas o también puedes usar las 4 etiquetas predefinidas:

  • com.google.test.loops.player_experience: Para bucles que sirven como reproducción de la experiencia de un usuario real cuando juega. El objetivo de hacer pruebas con estos bucles es reproducir los problemas con los que podría toparse un usuario habitual cuando usa la app.
  • com.google.test.loops.gpu_compatibility: Para bucles destinados a probar problemas relacionados con la GPU. El objetivo de hacer pruebas con estos bucles es ejecutar código GPU que podría no ejecutarse correctamente en producción, para exponer problemas de hardware y de controladores.
  • com.google.test.loops.compatibility: Para bucles destinados a probar una amplia gama de problemas de compatibilidad, incluidos problemas de E/S y de OpenSSL.
  • com.google.test.loops.performance: Para bucles destinados a probar el rendimiento del dispositivo. Por ejemplo, podrías ejecutar un juego con la configuración gráfica más compleja, a fin de observar cómo se comporta un nuevo dispositivo.

Compatibilidad con App Licensing

Test Lab admite apps que usan el servicio de App Licensing, que ofrece Google Play. Si deseas comprobar correctamente las licencias cuando pruebas la app con Test Lab, debes publicar la app en el canal de producción de Play Store. Para probar la app en el canal Alfa o Beta mediante Test Lab, quita la comprobación de licencias antes de subir la app a Test Lab.

Problemas conocidos

La prueba de bucle de juego en Test Lab tiene los siguientes problemas conocidos:

  • Compatibilidad limitada para la API de Khronos Vulkan. Solo los siguientes dispositivos disponibles en Test Lab son compatibles con la API de Vulkan: Samsung Galaxy S7 (nivel de API 24) y Google Pixel (nivel de API 25).
  • Algunas fallas no son compatibles con los backtraces. Por ejemplo, algunas versiones liberadas pueden suprimir la salida del proceso debuggerd mediante prctl(PR_SET_DUMPABLE, 0). Para obtener más información, consulta debuggerd.
  • El nivel de API 19 no es compatible actualmente debido a errores de permisos de archivos.

Ejemplo de archivo de salida de prueba de bucle de juego

Puedes usar archivos de datos de salida formateados, como se muestra en el siguiente ejemplo, para mostrar los resultados de la prueba de bucle de juego en Firebase console. Las áreas que se muestran como /.../ pueden contener los campos personalizados que necesites, siempre y cuando no entren en conflicto con los nombres de otros campos utilizados en este archivo:

{
  "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
}