Las pruebas de juegos móviles presentan desafíos únicos que van mucho más allá del QA tradicional de aplicaciones móviles. Los juegos exigen rendimiento en tiempo real, experiencias multijugador fluidas y consumo optimizado de recursos en miles de configuraciones de dispositivos. Esta guía completa explora enfoques especializados de pruebas para aplicaciones de juegos móviles, desde monitoreo de rendimiento hasta pruebas automatizadas en Unity y Unreal Engine.

Introducción a los Desafíos de Pruebas de Juegos Móviles

Los juegos móviles operan en un entorno excepcionalmente exigente. A diferencia de las aplicaciones web o empresariales, los juegos deben mantener renderizado consistente a 60 FPS, responder a entradas táctiles en milisegundos, gestionar restricciones de memoria en dispositivos de gama baja y ofrecer experiencias atractivas en dispositivos que van desde teléfonos Android (como se discute en Mobile App Performance Testing: Metrics, Tools, and Best Practices) (como se discute en Appium 2.0: New Architecture and Cloud Integration for Modern Mobile Testing) económicos hasta iPhones insignia.

Desafíos clave específicos de pruebas de juegos móviles:

  • Variabilidad de rendimiento: El mismo código del juego funciona drásticamente diferente en varios hardwares
  • Requisitos en tiempo real: Caídas de frames y latencia impactan directamente la experiencia de juego
  • Restricciones de recursos: Batería, memoria y límites térmicos afectan el comportamiento del juego
  • Dependencia de red: Juegos multijugador requieren manejo robusto de conectividad
  • Complejidad de monetización: Compras in-app, anuncios y economías virtuales necesitan pruebas rigurosas
  • Actualizaciones frecuentes: Los juegos reciben actualizaciones de contenido más frecuentemente que las apps típicas

Probar juegos móviles requiere tanto habilidades tradicionales de QA como conocimiento especializado de renderizado gráfico, motores de juego, perfilado de rendimiento y métricas de experiencia del jugador.

Pruebas de Rendimiento: FPS, Caídas de Frames y Renderizado

La tasa de frames es la métrica de rendimiento más crítica para juegos móviles. Los jugadores notan inmediatamente cuando los FPS caen por debajo de 60 (o 30 para dispositivos de gama baja), lo que lleva a malas reseñas y abandono de usuarios.

Enfoques de Medición de FPS

Integración con Unity Profiler:

using UnityEngine;
using UnityEngine.Profiling;

public class FPSMonitor : MonoBehaviour
{
    private float deltaTime = 0.0f;
    private int frameCount = 0;
    private float fpsSum = 0.0f;

    void Update()
    {
        deltaTime += (Time.unscaledDeltaTime - deltaTime) * 0.1f;
        float fps = 1.0f / deltaTime;

        frameCount++;
        fpsSum += fps;

        // Registrar métricas cada 60 frames
        if (frameCount >= 60)
        {
            float avgFPS = fpsSum / frameCount;
            LogPerformanceMetric("AvgFPS", avgFPS);
            LogPerformanceMetric("MemoryUsage", Profiler.GetTotalAllocatedMemoryLong() / 1048576f);

            frameCount = 0;
            fpsSum = 0.0f;
        }
    }

    void LogPerformanceMetric(string metricName, float value)
    {
        Debug.Log($"[Performance] {metricName}: {value:F2}");
        // Enviar a servicio de analytics
    }
}

Android ADB Frame Stats:

# Monitorear FPS en tiempo real en dispositivo Android
adb shell dumpsys gfxinfo com.tujuego.paquete framestats

# Extraer datos de timing de frames
adb shell dumpsys gfxinfo com.tujuego.paquete | grep "50th\|90th\|95th\|99th"

# Monitoreo continuo de FPS con timestamp
while true; do
  echo "$(date +%H:%M:%S) - $(adb shell dumpsys gfxinfo com.tujuego.paquete | grep 'Total frames rendered')"
  sleep 5
done

iOS Instruments:

Usar la plantilla Game Performance de Xcode Instruments para monitorear:

  • Tasa de frames (FPS)
  • Utilización de GPU
  • Uso de CPU por núcleo
  • Asignaciones de memoria
  • Tiempo de compilación de shaders

Análisis de Caídas de Frames

Las caídas de frames ocurren cuando el renderizado toma más tiempo que el presupuesto de frame (16.67ms para 60 FPS, 33.33ms para 30 FPS).

Objetivo FPSPresupuesto FrameCaídas AceptablesUmbral Crítico
60 FPS16.67ms<5% frames >20ms>10% frames >20ms
30 FPS33.33ms<5% frames >40ms>10% frames >40ms
120 FPS8.33ms<5% frames >12ms>10% frames >12ms

Causas comunes de caídas de frames:

  1. Picos de draw calls: Demasiados objetos renderizados simultáneamente
  2. Presión de GC: Pausas de recolección de basura en Unity/C#
  3. Cálculos de física: Detección de colisión compleja
  4. Compilación de shaders: Carga de shader por primera vez
  5. Carga de assets: Carga sincrónica de recursos durante gameplay

Pruebas de Consumo de Memoria y Batería

Los dispositivos móviles tienen límites estrictos de memoria y restricciones de batería. Los juegos deben optimizar ambos para prevenir crashes y reseñas negativas.

Estrategia de Pruebas de Memoria

Unity Memory Profiler:

using UnityEngine;
using System;

public class MemoryTracker : MonoBehaviour
{
    private long lastMemoryUsage = 0;

    public void TrackMemoryUsage(string sceneName)
    {
        // Forzar recolección de basura para medición precisa
        GC.Collect();
        System.Threading.Thread.Sleep(100);

        long totalMemory = GC.GetTotalMemory(false);
        long nativeMemory = UnityEngine.Profiling.Profiler.GetTotalAllocatedMemoryLong();

        Debug.Log($"[Memory] Scene: {sceneName}");
        Debug.Log($"  Managed Heap: {totalMemory / 1048576f:F2} MB");
        Debug.Log($"  Native Memory: {nativeMemory / 1048576f:F2} MB");
        Debug.Log($"  Delta: {(nativeMemory - lastMemoryUsage) / 1048576f:F2} MB");

        lastMemoryUsage = nativeMemory;

        // Alertar si la memoria excede umbrales
        if (nativeMemory > 1024 * 1048576) // 1GB
        {
            Debug.LogWarning("Uso de memoria excede 1GB - riesgo potencial de crash en dispositivos de gama baja");
        }
    }
}

Checklist de pruebas de memoria:

  • Uso base de memoria en menú principal
  • Crecimiento de memoria durante sesiones extendidas de juego (30+ minutos)
  • Uso pico de memoria durante escenas intensivas
  • Memoria liberada después de transiciones de escena
  • Huella de memoria de texturas por configuración de calidad
  • Detección de fugas de memoria (uso creciente sin meseta)

Pruebas de Consumo de Batería

Android Battery Stats:

# Resetear estadísticas de batería
adb shell dumpsys batterystats --reset

# Jugar juego durante duración de prueba (ej., 30 minutos)

# Extraer datos de consumo de batería
adb shell dumpsys batterystats com.tujuego.paquete

# Obtener uso específico de batería de la app
adb shell dumpsys batterystats | grep -A 20 "com.tujuego.paquete"

Objetivos de optimización de batería:

Tier DispositivoDrenaje Máx BateríaDuración PruebaTemp Aceptable
Flagship20% por hora1 hora<42°C
Gama media25% por hora1 hora<45°C
Gama baja30% por hora1 hora<48°C

Contribuidores al drenaje de batería:

  1. Renderizado GPU: Gráficos de alta calidad, efectos de post-procesamiento
  2. Actividad de red: Llamadas API frecuentes, multijugador en tiempo real
  3. Brillo de pantalla: Siempre probar al 100% de brillo
  4. Servicios en segundo plano: Analytics, anuncios, notificaciones push
  5. Wake locks: Prevenir suspensión del dispositivo durante gameplay

Pruebas de Latencia de Red y Multijugador

Los juegos multijugador son extremadamente sensibles a las condiciones de red. Las pruebas deben cubrir varios escenarios de conectividad.

Medición de Latencia

Prueba de Ping Multijugador Unity:

using UnityEngine;
using System.Net.NetworkInformation;
using System.Diagnostics;

public class NetworkMonitor : MonoBehaviour
{
    private Ping ping;
    private Stopwatch stopwatch;

    public void MeasureLatency(string serverAddress)
    {
        ping = new Ping();
        stopwatch = Stopwatch.StartNew();

        ping.SendAsync(serverAddress, 1000, null);
        ping.PingCompleted += PingCompletedCallback;
    }

    private void PingCompletedCallback(object sender, PingCompletedEventArgs e)
    {
        if (e.Reply != null && e.Reply.Status == IPStatus.Success)
        {
            long latency = e.Reply.RoundtripTime;
            LogLatencyMetric(latency);

            if (latency > 150)
                UnityEngine.Debug.LogWarning($"Alta latencia detectada: {latency}ms");
        }
    }

    private void LogLatencyMetric(long latency)
    {
        UnityEngine.Debug.Log($"[Network] Latency: {latency}ms");
        // Categorizar experiencia
        string quality = latency < 50 ? "Excelente" :
                        latency < 100 ? "Buena" :
                        latency < 150 ? "Regular" : "Pobre";
        UnityEngine.Debug.Log($"[Network] Calidad de Conexión: {quality}");
    }
}

Pruebas de Condiciones de Red

Escenarios de prueba:

EscenarioLatenciaPérdida PaquetesAncho BandaComportamiento Esperado
WiFi Excelente20-50ms0%50 MbpsCalidad completa, sin lag
4G Bueno50-100ms0-1%20 MbpsGameplay fluido
4G Pobre100-200ms1-3%5 MbpsCompensación latencia activa
3G200-500ms3-5%2 MbpsCalidad reducida, advertencias
Cambio redVaríaPicosVaríaManejo de reconexión

Herramientas para simulación de red:

  • Charles Proxy: Limitar ancho de banda, simular latencia
  • Network Link Conditioner (iOS): Perfiles de red preestablecidos
  • Opciones Desarrollador Android: Limitar datos en segundo plano
  • Unity Network Simulator: Emulación integrada de condiciones de red

Unity Testing Framework y Automatización de Pruebas

Unity proporciona frameworks completos de pruebas para testing automatizado de juegos.

Unity Test Framework

Ejemplo de Prueba PlayMode:

using UnityEngine;
using UnityEngine.TestTools;
using NUnit.Framework;
using System.Collections;

public class GameplayTests
{
    [UnityTest]
    public IEnumerator PlayerTakesDamageCorrectly()
    {
        // Arrange: Cargar escena de juego
        UnityEngine.SceneManagement.SceneManager.LoadScene("GameScene");
        yield return null; // Esperar un frame para carga de escena

        var player = GameObject.FindObjectOfType<PlayerController>();
        int initialHealth = player.Health;

        // Act: Aplicar daño
        player.TakeDamage(25);
        yield return new WaitForSeconds(0.1f);

        // Assert: Verificar que la salud disminuyó
        Assert.AreEqual(initialHealth - 25, player.Health);
        Assert.IsTrue(player.IsAlive);
    }

    [UnityTest]
    public IEnumerator GameMaintains60FPSUnderLoad()
    {
        // Arrange: Generar 100 enemigos
        var enemyPrefab = Resources.Load<GameObject>("Enemy");
        for (int i = 0; i < 100; i++)
        {
            GameObject.Instantiate(enemyPrefab, Random.insideUnitSphere * 50, Quaternion.identity);
        }

        yield return null;

        // Act: Monitorear FPS por 5 segundos
        float testDuration = 5.0f;
        float elapsed = 0;
        int frameCount = 0;
        float totalFPS = 0;

        while (elapsed < testDuration)
        {
            totalFPS += 1.0f / Time.unscaledDeltaTime;
            frameCount++;
            elapsed += Time.unscaledDeltaTime;
            yield return null;
        }

        float avgFPS = totalFPS / frameCount;

        // Assert: FPS promedio debe estar sobre 55 (permitiendo margen de 5 FPS)
        Assert.Greater(avgFPS, 55f, $"FPS promedio fue {avgFPS:F1}, esperado >55");
    }
}

Pruebas EditMode para Lógica de Juego

using NUnit.Framework;

public class InventorySystemTests
{
    private InventorySystem inventory;

    [SetUp]
    public void Setup()
    {
        inventory = new InventorySystem(maxSlots: 20);
    }

    [Test]
    public void AddItem_IncreasesItemCount()
    {
        // Arrange
        var item = new Item("Health Potion", ItemType.Consumable);

        // Act
        bool added = inventory.AddItem(item);

        // Assert
        Assert.IsTrue(added);
        Assert.AreEqual(1, inventory.ItemCount);
    }

    [Test]
    public void AddItem_ExceedingMaxSlots_ReturnsFalse()
    {
        // Arrange
        for (int i = 0; i < 20; i++)
        {
            inventory.AddItem(new Item($"Item{i}", ItemType.Material));
        }

        // Act
        bool added = inventory.AddItem(new Item("ExtraItem", ItemType.Material));

        // Assert
        Assert.IsFalse(added);
        Assert.AreEqual(20, inventory.ItemCount);
    }
}

Enfoques de Pruebas en Unreal Engine

Unreal Engine proporciona el framework de Automation Testing y Gauntlet para pruebas de juegos.

Pruebas de Automatización Unreal

Ejemplo de Prueba Funcional en C++:

#include "Tests/AutomationCommon.h"
#include "Misc/AutomationTest.h"

IMPLEMENT_SIMPLE_AUTOMATION_TEST(
    FPlayerMovementTest,
    "Game.Player.Movement",
    EAutomationTestFlags::ApplicationContextMask | EAutomationTestFlags::ProductFilter
)

bool FPlayerMovementTest::RunTest(const FString& Parameters)
{
    // Arrange: Obtener personaje del jugador
    APlayerCharacter* Player = GetWorld()->SpawnActor<APlayerCharacter>();
    FVector InitialLocation = Player->GetActorLocation();

    // Act: Simular movimiento hacia adelante por 1 segundo
    Player->MoveForward(1.0f);
    GetWorld()->Tick(LEVELTICK_All, 1.0f);

    // Assert: El jugador debería haberse movido hacia adelante
    FVector FinalLocation = Player->GetActorLocation();
    TestTrue("Player moved forward", FinalLocation.X > InitialLocation.X);

    // Cleanup
    Player->Destroy();

    return true;
}

Framework Gauntlet para Pruebas de Integración

Prueba Funcional en Blueprint:

Gauntlet permite pruebas de gameplay scripteadas:

  1. Crear escenarios de prueba en Blueprint
  2. Definir condiciones de éxito/fallo
  3. Ejecutar pruebas en servidores de build
  4. Generar reportes de prueba con capturas de pantalla

Ejemplo de controlador de prueba Gauntlet:

class FGamePerformanceTest : public FAutomationTestBase
{
public:
    bool RunPerfTest()
    {
        // Lanzar juego con mapa específico
        LaunchGame("TestMap_Combat");

        // Esperar inicialización del juego
        WaitForGameReady();

        // Generar escenario de prueba (100 enemigos AI)
        SpawnEnemies(100);

        // Monitorear rendimiento por 60 segundos
        bool PassedFPSTest = MonitorFPS(60.0f, MinFPS: 30.0f);
        bool PassedMemoryTest = MonitorMemory(60.0f, MaxMB: 2048);

        return PassedFPSTest && PassedMemoryTest;
    }
};

Fragmentación de Dispositivos y Compatibilidad

Los juegos móviles deben funcionar en miles de configuraciones de dispositivos.

Estrategia de Cobertura de Dispositivos

Enfoque de pruebas basado en tiers:

TierCoberturaDispositivos EjemploPrioridad
Tier 1Top 5 dispositivosiPhone 15 Pro, Galaxy S24, Pixel 8Crítica
Tier 2Gama media populariPhone SE, Galaxy A54, Pixel 7aAlta
Tier 3Gama baja/legacyAndroid económico, iPhone 12Media
Tier 4Casos extremosTablets, plegables, resoluciones inusualesBaja

Factores críticos de fragmentación:

  1. Variaciones de GPU: Mali, Adreno, PowerVR, GPUs Apple se comportan diferente
  2. Resoluciones de pantalla: Probar relaciones de aspecto de 16:9 a 21:9
  3. Versiones de SO: Soportar 2-3 años de historial de SO
  4. Configuraciones de RAM: Dispositivos de 2GB a 12GB+ RAM
  5. Tipos de almacenamiento: UFS, eMMC afectan tiempos de carga

Pruebas Automatizadas de Dispositivos

Integración con Firebase Test Lab:

# test_matrix.yaml
platforms:
  - name: Android
    devices:
      - model: flame  # Pixel 4
        version: 29
        orientation: portrait
      - model: starqlteue  # Galaxy S9+
        version: 28
        orientation: landscape
      - model: OnePlus7
        version: 30
        orientation: portrait

test-targets:
  - game-launch-test
  - tutorial-completion-test
  - 30min-gameplay-test

Pruebas de Compras In-App y Monetización

La monetización de juegos requiere pruebas rigurosas de flujos de pago, economías virtuales e integraciones de anuncios.

Checklist de Pruebas IAP

Verificación de flujo de compra:

using UnityEngine;
using UnityEngine.Purchasing;

public class IAPTestValidator
{
    public void ValidatePurchaseFlow(Product product)
    {
        // Escenarios de prueba:
        // 1. Compra exitosa
        Assert.True(ProcessPurchase(product.transactionID));
        Assert.True(VerifyReceipt(product.receipt));
        Assert.True(GrantVirtualGoods(product.definition.id));

        // 2. Cancelación de compra
        CancelPurchase(product);
        Assert.False(WasVirtualGoodsGranted(product.definition.id));

        // 3. Restauración de compra
        RestorePurchases();
        Assert.True(NonConsumablesRestored());

        // 4. Fallo de red durante compra
        SimulateNetworkFailure();
        Assert.True(PurchaseQueuedForRetry(product));
    }
}

Casos de prueba IAP comunes:

  • Éxito de compra con entrega inmediata
  • Manejo de fallo de compra (fondos insuficientes, cancelada)
  • Interrupción de red durante compra
  • Validación de recibo (Apple/Google)
  • Restauración de compra en nuevo dispositivo
  • Renovación y expiración de suscripción
  • Manejo de reembolsos
  • Precisión de conversión de moneda

Pruebas de Integración de Anuncios

Escenarios de prueba para anuncios:

Tipo AnuncioCasos de PruebaCriterio de Éxito
Video RecompensadoCompletar reproducción, cierre temprano, sin anuncio disponibleRecompensa otorgada solo al completar
IntersticialTiming, limitación frecuencia, botón cerrarNo intrusivo, respeta cooldowns
BannerPosicionamiento, tasa de refresco, click-throughNo obstruye gameplay

Pruebas de Balance y Progresión del Juego

El balance del juego requiere pruebas basadas en datos y análisis de comportamiento del jugador.

Seguimiento de Métricas de Progresión

using UnityEngine;

public class ProgressionAnalytics
{
    public void TrackLevelCompletion(int levelID, float completionTime, int attempts)
    {
        // Calcular métricas de dificultad
        float avgCompletionTime = GetAverageCompletionTime(levelID);
        float completionRate = GetCompletionRate(levelID);

        // Señalar problemas de balance
        if (completionRate < 0.4f)
        {
            Debug.LogWarning($"Nivel {levelID} tiene baja tasa de completación: {completionRate:P0}");
        }

        if (completionTime > avgCompletionTime * 2)
        {
            Debug.Log($"Jugador luchó con nivel {levelID} - tomó {completionTime:F1}s vs promedio {avgCompletionTime:F1}s");
        }

        // Seguir ritmo de progresión
        LogMetric("level_completion", new {
            level = levelID,
            duration = completionTime,
            attempts = attempts,
            player_level = GetPlayerLevel(),
            equipment_power = GetEquipmentPower()
        });
    }
}

Áreas de enfoque de pruebas de balance:

  1. Balance de economía: Tasas de ganancia vs gasto de moneda
  2. Curva de dificultad: Incremento gradual de desafío
  3. Tiempo de progresión: Horas necesarias para avance significativo
  4. Presión de monetización: Brecha de experiencia F2P vs jugadores de pago
  5. Bucles de engagement: Tasas de completación de misiones diarias

Pruebas de Carga y Estrés para Juegos Online

Los juegos online requieren pruebas robustas del lado del servidor.

Estrategia de Pruebas de Carga

Script de simulación para prueba de estrés de matchmaking:

import asyncio
import aiohttp
import time

class GameServerLoadTest:
    def __init__(self, server_url, concurrent_users):
        self.server_url = server_url
        self.concurrent_users = concurrent_users
        self.results = []

    async def simulate_player(self, player_id):
        async with aiohttp.ClientSession() as session:
            # Conectar a servidor
            start_time = time.time()

            async with session.ws_connect(f"{self.server_url}/game") as ws:
                # Autenticar
                await ws.send_json({
                    "action": "authenticate",
                    "player_id": player_id
                })

                # Unirse a matchmaking
                await ws.send_json({
                    "action": "join_matchmaking",
                    "game_mode": "ranked"
                })

                # Esperar partida
                match_found = False
                while not match_found:
                    msg = await ws.receive_json()
                    if msg["type"] == "match_found":
                        match_time = time.time() - start_time
                        self.results.append({
                            "player_id": player_id,
                            "match_time": match_time
                        })
                        match_found = True

    async def run_test(self):
        tasks = [
            self.simulate_player(f"player_{i}")
            for i in range(self.concurrent_users)
        ]
        await asyncio.gather(*tasks)

        # Analizar resultados
        avg_match_time = sum(r["match_time"] for r in self.results) / len(self.results)
        print(f"Tiempo promedio de matchmaking: {avg_match_time:.2f}s")
        print(f"Partidas exitosas: {len(self.results)}/{self.concurrent_users}")

# Ejecutar prueba con 1000 jugadores concurrentes
test = GameServerLoadTest("wss://game-server.example.com", 1000)
asyncio.run(test.run_test())

Objetivos de pruebas de carga:

MétricaObjetivoAdvertenciaCrítico
Usuarios concurrentes10,000+5,000<2,000
Tiempo matchmaking<10s10-20s>30s
Tiempo respuesta servidor<100ms100-200ms>300ms
Pérdida paquetes<0.5%0.5-2%>3%

Pruebas de Calidad Gráfica en Dispositivos

La calidad visual debe escalar apropiadamente en los tiers de dispositivos.

Validación de Configuraciones de Calidad

Prueba automatizada de preset de calidad:

using UnityEngine;

public class QualityPresetTester : MonoBehaviour
{
    [System.Serializable]
    public class QualityBenchmark
    {
        public string qualityLevel;
        public float minFPS;
        public float maxMemoryMB;
        public float testDuration;
    }

    public QualityBenchmark[] benchmarks = new QualityBenchmark[]
    {
        new QualityBenchmark { qualityLevel = "Low", minFPS = 30, maxMemoryMB = 512, testDuration = 60 },
        new QualityBenchmark { qualityLevel = "Medium", minFPS = 45, maxMemoryMB = 768, testDuration = 60 },
        new QualityBenchmark { qualityLevel = "High", minFPS = 60, maxMemoryMB = 1024, testDuration = 60 }
    };

    public void RunQualityTests()
    {
        foreach (var benchmark in benchmarks)
        {
            QualitySettings.SetQualityLevel(GetQualityLevelIndex(benchmark.qualityLevel));

            float avgFPS = MeasureAverageFPS(benchmark.testDuration);
            float peakMemory = MeasurePeakMemory(benchmark.testDuration);

            bool fpsPass = avgFPS >= benchmark.minFPS;
            bool memoryPass = peakMemory <= benchmark.maxMemoryMB;

            Debug.Log($"Calidad: {benchmark.qualityLevel} - FPS: {avgFPS:F1} (objetivo: {benchmark.minFPS}) - Memoria: {peakMemory:F0}MB (máx: {benchmark.maxMemoryMB}MB)");
            Debug.Log($"Resultado: {(fpsPass && memoryPass ? "PASS" : "FAIL")}");
        }
    }
}

Pruebas de regresión visual:

Usar herramientas de comparación de capturas de pantalla para detectar cambios visuales no intencionados:

  1. Capturar capturas de pantalla base para cada nivel de calidad
  2. Después de cambios de código, capturar nuevas capturas
  3. Comparar diferencias de píxeles usando herramientas de diff de imagen
  4. Señalar cambios que excedan umbral (ej., >5% diferencia de píxeles)

Pruebas de Audio y Hápticos

El sonido y la retroalimentación háptica impactan significativamente la experiencia del jugador.

Checklist de Pruebas de Audio

Verificación de implementación de audio:

  • Música de fondo hace loop sin problemas
  • Efectos de sonido se activan en eventos correctos del juego
  • Ducking de audio durante diálogos
  • Configuraciones de volumen persisten entre sesiones
  • Audio no continúa cuando app está en segundo plano
  • Posicionamiento de audio espacial (sonido 3D)
  • Impacto de rendimiento de audio (uso de CPU)

Pruebas de hápticos:

using UnityEngine;

public class HapticsValidator : MonoBehaviour
{
    public void TestHapticFeedback()
    {
        // Probar háptico ligero
        Handheld.Vibrate();  // Impacto ligero iOS

        // Validar disparadores hápticos:
        // - Presión de botón: Háptico ligero
        // - Recolección de ítem: Háptico medio
        // - Daño al jugador: Háptico fuerte
        // - Game over: Vibración en patrón

        // Verificar que háptico respeta:
        // - Modo silencioso del dispositivo (iOS)
        // - Configuración de preferencia del usuario
        // - Modo ahorro de batería
    }
}

CI/CD para Proyectos de Juegos

Los pipelines automatizados de build y testing son esenciales para desarrollo de juegos.

Integración con Unity Cloud Build

Ejemplo de configuración de build:

# unity-cloud-build.yaml
targets:
  android-production (como se discute en [Cross-Platform Mobile Testing: Strategies for Multi-Device Success](/blog/cross-platform-mobile-testing)):
    platform: android
    scriptingBackend: il2cpp
    buildSettings:
      development: false
      compressionMethod: lz4
    pre-build-script: Scripts/PreBuild.sh
    post-build-script: Scripts/PostBuild.sh

  ios-production:
    platform: ios
    scriptingBackend: il2cpp
    xcodeVersion: latest
    buildSettings:
      development: false

test-suites:
  unit-tests:
    platform: editmode
    testCategories: [Unit, Integration]

  playmode-tests:
    platform: playmode
    testCategories: [Functional, Performance]
    minPassRate: 95%

GitHub Actions para Pruebas de Juegos

name: Game Build and Test

on:
  push:
    branches: [main, develop]
  pull_request:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - uses: game-ci/unity-test-runner@v2
        env:
          UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
        with:
          testMode: all
          artifactsPath: test-results

      - name: Upload test results
        uses: actions/upload-artifact@v3
        with:
          name: Test results
          path: test-results

  build:
    needs: test
    runs-on: ubuntu-latest
    strategy:
      matrix:
        platform: [Android, iOS]
    steps:
      - uses: game-ci/unity-builder@v2
        env:
          UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
        with:
          targetPlatform: ${{ matrix.platform }}

      - name: Deploy to TestFlight/Play Console
        run: ./deploy-scripts/${{ matrix.platform }}.sh

Reportes automatizados de pruebas:

  • Tasas de éxito de pruebas unitarias
  • Benchmarks de rendimiento (FPS, memoria)
  • Seguimiento de tamaño de build
  • Reportes de crash de dispositivos de prueba
  • Métricas de cobertura de código

Conclusión

Las pruebas de juegos móviles demandan experiencia especializada más allá del QA tradicional. El éxito requiere:

  • Monitoreo de rendimiento: Seguimiento continuo de FPS, memoria y batería
  • Pruebas de red: Medición de latencia y cobertura de escenarios de conectividad
  • Automatización: Unity Test Framework y pruebas de Automatización Unreal
  • Cobertura de dispositivos: Pruebas estratégicas en tiers de dispositivos
  • Validación de monetización: Pruebas rigurosas de integración IAP y anuncios
  • Pruebas de balance: Análisis de progresión y economía basado en datos
  • Integración CI/CD: Pipelines automatizados de builds y pruebas

Al implementar estrategias completas de pruebas que cubran rendimiento, funcionalidad, compatibilidad y experiencia del jugador, los equipos de QA aseguran que los juegos móviles entreguen experiencias estables y atractivas en diversos dispositivos y condiciones de red. La inversión en infraestructura robusta de pruebas paga dividendos a través de mayor retención de jugadores, mejores reseñas y menos problemas post-lanzamiento.