Comienza a realizar pruebas de bucle de juego

La automatización de las pruebas de videojuegos puede ser una tarea complicada cuando este tipo de apps se crean en frameworks de IU diferentes. Las pruebas de bucle de juego te permiten integrar tus pruebas nativas a Test Lab y ejecutarlas fácilmente en los dispositivos que quieras. De esta manera, se ejecutan tus pruebas a través de tu app de juego, a la vez que simulan las acciones de un jugador real. En esta guía, se muestra cómo ejecutar una prueba de bucle de juego y, luego, ver y administrar los resultados de la prueba en Firebase console.

Según el motor de juego, puedes implementar pruebas con uno o varios bucles. Un bucle es una ejecución completa o parcial de tu prueba en la app de juego y se puede usar para lo siguiente:

  • Ejecutar un nivel del juego de la misma manera en que lo jugaría un usuario final. Puedes escribir una secuencia de comandos de entradas del usuario, dejar que el usuario esté inactivo o reemplazarlo por una IA si tiene sentido en tu juego (p. ej., si tienes una app de carreras de autos y ya implementaste una IA, puedes poner fácilmente un controlador de IA a cargo de la entrada 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 sombreadores, ejecutarlos, comprobar que el resultado sea el esperado, etcétera)

Puedes ejecutar pruebas de bucle de juego en un solo dispositivo de prueba, en un conjunto de dispositivos de prueba o en Test Lab. Sin embargo, te recomendamos ejecutar las pruebas en dispositivos físicos porque la velocidad de fotogramas de gráficos en estos es mayor que la de los dispositivos virtuales.

Antes de comenzar

Antes de implementar una prueba, debes configurar tu app para que admita las pruebas de bucle de juego.

  1. En el manifiesto de la app, agrega un nuevo filtro de intents a la actividad:

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

    Esto permite que Test Lab inicie el videojuego activándolo con un intent específico.

  2. En tu código (recomendamos hacerlo dentro de la declaración del método onCreate), agrega lo siguiente:

    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
    }

    Esto permite que tu actividad verifique el intent que inicia la app. También puedes agregar este código más adelante si lo prefieres (p. ej., después de cargar inicialmente el motor de juego).

  3. Se recomienda agregar lo siguiente al final de la prueba:

    Kotlin+KTX

    yourActivity.finish()

    Java

    yourActivity.finish();

    Esto cierra la app cuando finaliza la prueba de bucle de juego. La prueba depende del framework de la IU de tu app para iniciar el bucle siguiente y, cuando se cierra la app, le indica que la prueba finalizó.

Crea y ejecuta pruebas de bucle de juego

Después de configurar tu app para que ejecute pruebas de bucle de juego, puedes crear una prueba de inmediato y ejecutarla en tu app de juego. Puedes ejecutar las pruebas en Test Lab mediante Firebase console o la interfaz de línea de comandos (CLI) de gcloud, o bien en un dispositivo local con Test Loop Manager.

Ejecuta pruebas en un dispositivo local

Test Loop Manager de Test Lab es una app de código abierto que te permite integrar pruebas de bucle de juego y ejecutarlas en tus dispositivos locales. También permite que el equipo de control de calidad ejecute los mismos bucles de juego en sus dispositivos.

Sigue estos pasos para ejecutar una prueba en un dispositivo local con Test Loop Manager:

  1. Ejecuta el siguiente comando para descargar Test Loop Manager en un teléfono o una tablet:
    adb install testloopmanager.apk
  2. En tu teléfono o tablet, abre la app de Test Loop Apps. En esta se muestra una lista de las apps de tu dispositivo que se pueden ejecutar con bucles de juego. Si no ves tu app de juego, asegúrate de que el filtro de intents coincida con el que se describe en el primer paso de la sección Antes de comenzar.
  3. Selecciona la app de juego y la cantidad de bucles que deseas ejecutar. Nota: En este paso, puedes optar por ejecutar un subconjunto de bucles en lugar de solo uno. Si necesitas más información para ejecutar varios bucles a la vez, consulta la sección Funciones opcionales.
  4. Haz clic en Run test, y la prueba comenzará a ejecutarse de inmediato.

Ejecuta pruebas en Test Lab

Puedes ejecutar una prueba de bucle de juego en Test Lab con Firebase console o la CLI de gcloud. Antes de comenzar, si no tienes un proyecto, abre Firebase console y crea uno.

Usa Firebase console

  1. En el panel izquierdo de Firebase console, haz clic en Test Lab.
  2. Haz clic en Ejecutar tu primera prueba (o Ejecutar una prueba si ya se ejecutó una en el proyecto).
  3. Selecciona el tipo de prueba Bucle de juego y luego haz clic en Continuar.
  4. Haz clic en Explorar y selecciona el archivo .apk de tu app. Nota: En este paso, puedes optar por ejecutar un subconjunto de bucles en lugar de solo uno. Si necesitas más información para ejecutar varios bucles a la vez, consulta la sección Funciones opcionales.
  5. Haz clic en Continuar.
  6. Selecciona los dispositivos físicos que se utilizarán para probar la app.
  7. Haz clic en Iniciar pruebas.

Si quieres obtener más información para comenzar a usar Firebase console, consulta el artículo Comienza a realizar pruebas con Firebase console.

Usa la línea de comandos de gcloud (CLI)

  1. Si aún no lo has hecho, descarga e instala el SDK de Google Cloud.

  2. Accede a gcloud CLI con tu Cuenta de Google:

    gcloud auth login

  3. Configura tu proyecto de Firebase en gcloud, en el que PROJECT_ID es el ID del proyecto:

    gcloud config set project PROJECT_ID
    
  4. Ejecuta tu primera prueba:

    gcloud firebase test android run \
     --type=game-loop --app=<var>path-to-apk</var> \
     --device model=herolte,version=23
    

Si quieres obtener más información para comenzar a usar la línea de comandos de gcloud, consulta el artículo Comienza a realizar pruebas con la CLI de gcloud.

Funciones opcionales

Test Lab ofrece varias funciones opcionales que te permiten personalizar aún más las pruebas, incluida la capacidad de escribir datos de salida, compatibilidad con varios bucles de juego y etiquetas para bucles relacionados.

Escribe datos de salida

Las pruebas de bucle de juego pueden escribir los resultados en un archivo especificado en el método launchIntent.getData(). Después de ejecutar una prueba, puedes acceder a estos datos de salida en la sección Test Lab de Firebase console (consulta el ejemplo de archivo de salida de prueba de bucle de juego).

Test Lab sigue las prácticas recomendadas que se describen en la guía Cómo compartir un archivo para compartir un archivo con otra app. En el método onCreate() de tu actividad, que es donde se encuentra tu intent, puedes ejecutar el siguiente código para verificar el archivo de salida de datos:

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());
    // ...
}

Si deseas escribir en el archivo desde el lado C++ de tu app de juego, puedes pasar el descriptor de archivo en lugar de la ruta de acceso del archivo:

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

Ejemplo de archivo de salida

Puedes usar archivos de datos de salida (con un formato como el del siguiente ejemplo) para mostrar los resultados de las pruebas de bucle de juego en la sección Test Lab de 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
}

Varios bucles de juego

Es posible que te resulte útil ejecutar varios bucles de juego en tu app. Un bucle es una ejecución completa de tu app de juego de principio a fin. 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 tu app falla en el nivel 32, puedes iniciar directamente ese bucle de juego para reproducir la falla y probar correcciones de errores.

Sigue estos pasos para que la app ejecute varios bucles al mismo tiempo:

  • Si quieres usar Test Loop Manager para ejecutar una prueba, haz lo siguiente:

    1. Agrega la siguiente línea al manifiesto de la app, dentro del elemento <application>:

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

      Este intent de inicio contiene el bucle de destino como un parámetro de número entero. En el campo android:value, puedes especificar un número entero del 1 al 1,024 (la cantidad máxima de bucles permitidos para una sola prueba). Ten en cuenta que los bucles se indexan a partir del 1, no del 0.

    2. En la app Test Loop Manager, aparece una pantalla de selección que te permite seleccionar los bucles que deseas ejecutar. Si seleccionas varios, cada uno se inicia en secuencia después de que se completa el bucle anterior.

  • Si ejecutas una prueba con Firebase console, ingresa una lista o un rango de números de bucle en el campo Situaciones.

  • Si ejecutas una prueba con la CLI de gcloud, especifica una lista de números de bucle con la marca --scenario-numbers. Por ejemplo, --scenario-numbers=1,3,5 ejecuta los bucles 1, 3 y 5.

  • Si escribes en lenguaje C++ y quieres cambiar el comportamiento del bucle, pasa el siguiente código adicional a tu código nativo de C++:

    Kotlin+KTX

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

    Java

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

    Ahora puedes cambiar el comportamiento de tu bucle en función del valor int resultante.

Etiqueta los bucles de juego

Cuando etiquetas tus bucles de juego con una o más etiquetas de situaciones, tú y el equipo de control de calidad pueden iniciar fácilmente un conjunto de bucles de juego relacionados (p. ej., “todos los bucles de juego de compatibilidad”) y probarlos en una sola matriz. Puedes crear tus propias etiquetas o usar las predefinidas que ofrece Test Lab:

  • 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 para observar cómo se comporta un nuevo dispositivo.

Sigue estos pasos para permitir que tu app ejecute bucles con la misma etiqueta.

  • Si quieres usar Test Loop Manager para ejecutar una prueba, haz lo siguiente:

    1. En el manifiesto de la app, agrega la siguiente línea de metadatos y reemplaza LABEL_NAME por la etiqueta que prefieras:

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

      En el campo android:value puedes especificar un intervalo o un conjunto de números enteros de 1 a 1,024 (la cantidad máxima de bucles permitidos para una sola prueba) que represente la cantidad de bucles que quieres etiquetar. Ten en cuenta que los bucles se indexan a partir del 1, no del 0. Por ejemplo, android:value="1,3-5" aplica LABEL_NAME a los bucles 1, 3, 4 y 5.

    2. En la app de Test Loop Manager, ingresa una o más etiquetas en el campo Etiquetas.

  • Si usas Firebase console para ejecutar una prueba, ingresa una o más etiquetas en el campo Etiquetas.

  • Si ejecutas una prueba con la CLI de gcloud, especifica una o más etiquetas de situación con la marca --scenario-labels (p. ej., --scenario-labels=performance,gpu).

Compatibilidad con App Licensing

Test Lab admite apps que usan el servicio de App Licensing, que ofrece Google Play. Si quieres 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 probarla 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

Las pruebas de bucle de juego en Test Lab tienen los siguientes problemas conocidos:

  • Algunas fallas no son compatibles con los backtraces. Por ejemplo, algunas compilaciones de lanzamiento 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.