Тестирование мобильных игр представляет уникальные вызовы, которые выходят далеко за рамки традиционного QA мобильных приложений. Игры требуют производительности в реальном времени, бесшовного мультиплеерного опыта и оптимизированного потребления ресурсов на тысячах конфигураций устройств. Это подробное руководство исследует специализированные подходы к тестированию мобильных игровых приложений, от мониторинга производительности до автоматизированного тестирования в Unity и Unreal Engine.
Введение в Вызовы Тестирования Мобильных Игр
Мобильные игры работают в исключительно требовательной среде. В отличие от веб-приложений или корпоративных приложений, игры должны поддерживать стабильный рендеринг на 60 FPS, отвечать на сенсорный ввод в течение миллисекунд, управлять ограничениями памяти на устройствах низкого уровня и обеспечивать увлекательный опыт на устройствах от бюджетных Android-телефонов (как обсуждается в Mobile App Performance Testing: Metrics, Tools, and Best Practices) (как обсуждается в Appium 2.0: New Architecture and Cloud Integration for Modern Mobile Testing) до флагманских iPhone.
Ключевые вызовы, специфичные для тестирования мобильных игр:
- Вариативность производительности: Один и тот же код игры работает радикально по-разному на различном оборудовании
- Требования реального времени: Просадки кадров и задержки напрямую влияют на игровой опыт
- Ограничения ресурсов: Батарея, память и термические лимиты влияют на поведение игры
- Зависимость от сети: Мультиплеерные игры требуют надежной обработки подключения
- Сложность монетизации: Внутриигровые покупки, реклама и виртуальные экономики нуждаются в тщательном тестировании
- Частые обновления: Игры получают обновления контента чаще, чем типичные приложения
Тестирование мобильных игр требует как традиционных навыков QA, так и специализированных знаний графического рендеринга, игровых движков, профилирования производительности и метрик пользовательского опыта.
Тестирование Производительности: FPS, Просадки Кадров и Рендеринг
Частота кадров - это самая критичная метрика производительности для мобильных игр. Игроки немедленно замечают, когда FPS падает ниже 60 (или 30 для устройств низкого уровня), что приводит к плохим отзывам и оттоку пользователей.
Подходы к Измерению FPS
Интеграция с 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;
// Логировать метрики каждые 60 кадров
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}");
// Отправить в сервис аналитики
}
}
Android ADB Frame Stats:
# Мониторинг FPS в реальном времени на Android устройстве
adb shell dumpsys gfxinfo com.yourgame.package framestats
# Извлечение данных о времени кадров
adb shell dumpsys gfxinfo com.yourgame.package | grep "50th\|90th\|95th\|99th"
# Непрерывный мониторинг FPS с временной меткой
while true; do
echo "$(date +%H:%M:%S) - $(adb shell dumpsys gfxinfo com.yourgame.package | grep 'Total frames rendered')"
sleep 5
done
iOS Instruments:
Использовать шаблон Game Performance в Xcode Instruments для мониторинга:
- Частота кадров (FPS)
- Использование GPU
- Использование CPU по ядрам
- Выделения памяти
- Время компиляции шейдеров
Анализ Просадок Кадров
Просадки кадров происходят, когда рендеринг занимает больше времени, чем бюджет кадра (16.67мс для 60 FPS, 33.33мс для 30 FPS).
Цель FPS | Бюджет Кадра | Допустимые Просадки | Критический Порог |
---|---|---|---|
60 FPS | 16.67мс | <5% кадров >20мс | >10% кадров >20мс |
30 FPS | 33.33мс | <5% кадров >40мс | >10% кадров >40мс |
120 FPS | 8.33мс | <5% кадров >12мс | >10% кадров >12мс |
Распространенные причины просадок кадров:
- Всплески draw calls: Слишком много объектов рендерится одновременно
- Давление GC: Паузы сборщика мусора в Unity/C#
- Расчеты физики: Сложное обнаружение столкновений
- Компиляция шейдеров: Первая загрузка шейдеров
- Загрузка ассетов: Синхронная загрузка ресурсов во время геймплея
Тестирование Потребления Памяти и Батареи
Мобильные устройства имеют строгие ограничения памяти и батареи. Игры должны оптимизировать оба аспекта, чтобы предотвратить крэши и негативные отзывы пользователей.
Стратегия Тестирования Памяти
Unity Memory Profiler:
using UnityEngine;
using System;
public class MemoryTracker : MonoBehaviour
{
private long lastMemoryUsage = 0;
public void TrackMemoryUsage(string sceneName)
{
// Принудительная сборка мусора для точного измерения
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;
// Предупредить, если память превышает пороги
if (nativeMemory > 1024 * 1048576) // 1GB
{
Debug.LogWarning("Использование памяти превышает 1GB - потенциальный риск краша на устройствах низкого уровня");
}
}
}
Чеклист тестирования памяти:
- Базовое использование памяти в главном меню
- Рост памяти во время продолжительных игровых сессий (30+ минут)
- Пиковое использование памяти во время интенсивных сцен
- Освобождение памяти после переходов сцен
- След памяти текстур на настройку качества
- Обнаружение утечек памяти (растущее использование без плато)
Тестирование Потребления Батареи
Android Battery Stats:
# Сброс статистики батареи
adb shell dumpsys batterystats --reset
# Игра в течение времени теста (например, 30 минут)
# Извлечение данных о потреблении батареи
adb shell dumpsys batterystats com.yourgame.package
# Получить конкретное использование батареи приложением
adb shell dumpsys batterystats | grep -A 20 "com.yourgame.package"
Цели оптимизации батареи:
Уровень Устройства | Макс. Расход Батареи | Длительность Теста | Приемлемая Темп. |
---|---|---|---|
Флагман | 20% в час | 1 час | <42°C |
Средний уровень | 25% в час | 1 час | <45°C |
Низкий уровень | 30% в час | 1 час | <48°C |
Факторы расхода батареи:
- Рендеринг GPU: Высококачественная графика, эффекты постобработки
- Сетевая активность: Частые API вызовы, мультиплеер в реальном времени
- Яркость экрана: Всегда тестировать на 100% яркости
- Фоновые сервисы: Аналитика, реклама, push-уведомления
- Wake locks: Предотвращение спящего режима устройства во время геймплея
Тестирование Задержки Сети и Мультиплеера
Мультиплеерные игры чрезвычайно чувствительны к сетевым условиям. Тестирование должно охватывать различные сценарии подключения.
Измерение Задержки
Тест Пинга Мультиплеера 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($"Обнаружена высокая задержка: {latency}ms");
}
}
private void LogLatencyMetric(long latency)
{
UnityEngine.Debug.Log($"[Network] Latency: {latency}ms");
// Категоризация опыта
string quality = latency < 50 ? "Отличное" :
latency < 100 ? "Хорошее" :
latency < 150 ? "Удовлетворительное" : "Плохое";
UnityEngine.Debug.Log($"[Network] Качество Соединения: {quality}");
}
}
Тестирование Сетевых Условий
Тестовые сценарии:
Сценарий | Задержка | Потеря Пакетов | Пропускная Способность | Ожидаемое Поведение |
---|---|---|---|---|
Отличный WiFi | 20-50мс | 0% | 50 Мбит/с | Полное качество, без лагов |
Хороший 4G | 50-100мс | 0-1% | 20 Мбит/с | Плавный геймплей |
Плохой 4G | 100-200мс | 1-3% | 5 Мбит/с | Компенсация задержки активна |
3G | 200-500мс | 3-5% | 2 Мбит/с | Снижено качество, предупреждения |
Переключение сети | Варьируется | Всплески | Варьируется | Обработка переподключения |
Инструменты для симуляции сети:
- Charles Proxy: Ограничение пропускной способности, симуляция задержки
- Network Link Conditioner (iOS): Предустановленные сетевые профили
- Параметры Разработчика Android: Ограничение фоновых данных
- Unity Network Simulator: Встроенная эмуляция сетевых условий
Unity Testing Framework и Автоматизация Тестирования
Unity предоставляет комплексные фреймворки для автоматизированного тестирования игр.
Unity Test Framework
Пример Теста PlayMode:
using UnityEngine;
using UnityEngine.TestTools;
using NUnit.Framework;
using System.Collections;
public class GameplayTests
{
[UnityTest]
public IEnumerator PlayerTakesDamageCorrectly()
{
// Arrange: Загрузить игровую сцену
UnityEngine.SceneManagement.SceneManager.LoadScene("GameScene");
yield return null; // Подождать один кадр для загрузки сцены
var player = GameObject.FindObjectOfType<PlayerController>();
int initialHealth = player.Health;
// Act: Применить урон
player.TakeDamage(25);
yield return new WaitForSeconds(0.1f);
// Assert: Проверить, что здоровье уменьшилось
Assert.AreEqual(initialHealth - 25, player.Health);
Assert.IsTrue(player.IsAlive);
}
[UnityTest]
public IEnumerator GameMaintains60FPSUnderLoad()
{
// Arrange: Заспавнить 100 врагов
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: Мониторить FPS в течение 5 секунд
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 должен быть выше 55 (допуская запас в 5 FPS)
Assert.Greater(avgFPS, 55f, $"Средний FPS был {avgFPS:F1}, ожидалось >55");
}
}
Тесты EditMode для Игровой Логики
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);
}
}
Подходы к Тестированию в Unreal Engine
Unreal Engine предоставляет фреймворк Automation Testing и Gauntlet для тестирования игр.
Тесты Автоматизации Unreal
Пример Функционального Теста на 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: Получить персонажа игрока
APlayerCharacter* Player = GetWorld()->SpawnActor<APlayerCharacter>();
FVector InitialLocation = Player->GetActorLocation();
// Act: Симулировать движение вперед в течение 1 секунды
Player->MoveForward(1.0f);
GetWorld()->Tick(LEVELTICK_All, 1.0f);
// Assert: Игрок должен был переместиться вперед
FVector FinalLocation = Player->GetActorLocation();
TestTrue("Player moved forward", FinalLocation.X > InitialLocation.X);
// Cleanup
Player->Destroy();
return true;
}
Фреймворк Gauntlet для Интеграционного Тестирования
Функциональный Тест в Blueprint:
Gauntlet позволяет скриптовое тестирование геймплея:
- Создать тестовые сценарии в Blueprint
- Определить условия успеха/провала
- Запустить тесты на серверах сборки
- Сгенерировать отчеты тестов со скриншотами
Пример контроллера теста Gauntlet:
class FGamePerformanceTest : public FAutomationTestBase
{
public:
bool RunPerfTest()
{
// Запустить игру с конкретной картой
LaunchGame("TestMap_Combat");
// Подождать инициализации игры
WaitForGameReady();
// Заспавнить тестовый сценарий (100 AI врагов)
SpawnEnemies(100);
// Мониторить производительность в течение 60 секунд
bool PassedFPSTest = MonitorFPS(60.0f, MinFPS: 30.0f);
bool PassedMemoryTest = MonitorMemory(60.0f, MaxMB: 2048);
return PassedFPSTest && PassedMemoryTest;
}
};
Фрагментация Устройств и Совместимость
Мобильные игры должны работать на тысячах конфигураций устройств.
Стратегия Покрытия Устройств
Подход тестирования на основе уровней:
Уровень | Покрытие | Примеры Устройств | Приоритет |
---|---|---|---|
Уровень 1 | Топ 5 устройств | iPhone 15 Pro, Galaxy S24, Pixel 8 | Критический |
Уровень 2 | Популярный средний уровень | iPhone SE, Galaxy A54, Pixel 7a | Высокий |
Уровень 3 | Низкий уровень/устаревшие | Бюджетный Android, iPhone 12 | Средний |
Уровень 4 | Крайние случаи | Планшеты, складные, необычные разрешения | Низкий |
Критические факторы фрагментации:
- Вариации GPU: Mali, Adreno, PowerVR, Apple GPU ведут себя по-разному
- Разрешения экрана: Тестировать соотношения сторон от 16:9 до 21:9
- Версии ОС: Поддерживать 2-3 года истории ОС
- Конфигурации RAM: Устройства с 2ГБ до 12ГБ+ RAM
- Типы хранилища: UFS, eMMC влияют на время загрузки
Автоматизированное Тестирование Устройств
Интеграция с 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
Тестирование Внутриигровых Покупок и Монетизации
Монетизация игр требует тщательного тестирования платежных потоков, виртуальных экономик и интеграций рекламы.
Чеклист Тестирования IAP
Проверка потока покупки:
using UnityEngine;
using UnityEngine.Purchasing;
public class IAPTestValidator
{
public void ValidatePurchaseFlow(Product product)
{
// Тестовые сценарии:
// 1. Успешная покупка
Assert.True(ProcessPurchase(product.transactionID));
Assert.True(VerifyReceipt(product.receipt));
Assert.True(GrantVirtualGoods(product.definition.id));
// 2. Отмена покупки
CancelPurchase(product);
Assert.False(WasVirtualGoodsGranted(product.definition.id));
// 3. Восстановление покупок
RestorePurchases();
Assert.True(NonConsumablesRestored());
// 4. Сбой сети во время покупки
SimulateNetworkFailure();
Assert.True(PurchaseQueuedForRetry(product));
}
}
Распространенные тестовые случаи IAP:
- Успешная покупка с немедленной доставкой
- Обработка провала покупки (недостаточно средств, отменена)
- Прерывание сети во время покупки
- Валидация чека (Apple/Google)
- Восстановление покупки на новом устройстве
- Возобновление и истечение подписки
- Обработка возвратов
- Точность конвертации валюты
Тестирование Интеграции Рекламы
Тестовые сценарии для рекламы:
Тип Рекламы | Тестовые Случаи | Критерий Успеха |
---|---|---|
Rewarded Video | Завершение воспроизведения, раннее закрытие, нет доступной рекламы | Награда выдается только при завершении |
Interstitial | Тайминг, ограничение частоты, кнопка закрытия | Ненавязчиво, соблюдает кулдауны |
Banner | Позиционирование, частота обновления, клик | Не мешает геймплею |
Тестирование Баланса Игры и Прогрессии
Баланс игры требует тестирования на основе данных и анализа поведения игроков.
Отслеживание Метрик Прогрессии
using UnityEngine;
public class ProgressionAnalytics
{
public void TrackLevelCompletion(int levelID, float completionTime, int attempts)
{
// Рассчитать метрики сложности
float avgCompletionTime = GetAverageCompletionTime(levelID);
float completionRate = GetCompletionRate(levelID);
// Отметить проблемы баланса
if (completionRate < 0.4f)
{
Debug.LogWarning($"Уровень {levelID} имеет низкий показатель завершения: {completionRate:P0}");
}
if (completionTime > avgCompletionTime * 2)
{
Debug.Log($"Игрок испытывал трудности с уровнем {levelID} - затратил {completionTime:F1}с против среднего {avgCompletionTime:F1}с");
}
// Отслеживать темп прогрессии
LogMetric("level_completion", new {
level = levelID,
duration = completionTime,
attempts = attempts,
player_level = GetPlayerLevel(),
equipment_power = GetEquipmentPower()
});
}
}
Области фокуса тестирования баланса:
- Баланс экономики: Скорость заработка против расхода валюты
- Кривая сложности: Постепенное увеличение вызова
- Время до прогрессии: Часы, необходимые для значимого продвижения
- Давление монетизации: Разрыв опыта F2P против платных игроков
- Циклы вовлечения: Показатели завершения ежедневных квестов
Нагрузочное и Стресс-Тестирование Онлайн-Игр
Онлайн-игры требуют надежного серверного тестирования.
Стратегия Нагрузочного Тестирования
Скрипт симуляции для стресс-теста матчмейкинга:
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:
# Подключиться к серверу
start_time = time.time()
async with session.ws_connect(f"{self.server_url}/game") as ws:
# Аутентификация
await ws.send_json({
"action": "authenticate",
"player_id": player_id
})
# Присоединиться к матчмейкингу
await ws.send_json({
"action": "join_matchmaking",
"game_mode": "ranked"
})
# Ждать матч
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)
# Анализировать результаты
avg_match_time = sum(r["match_time"] for r in self.results) / len(self.results)
print(f"Среднее время матчмейкинга: {avg_match_time:.2f}с")
print(f"Успешные матчи: {len(self.results)}/{self.concurrent_users}")
# Запустить тест с 1000 одновременных игроков
test = GameServerLoadTest("wss://game-server.example.com", 1000)
asyncio.run(test.run_test())
Цели нагрузочного тестирования:
Метрика | Цель | Предупреждение | Критично |
---|---|---|---|
Одновременные пользователи | 10,000+ | 5,000 | <2,000 |
Время матчмейкинга | <10с | 10-20с | >30с |
Время ответа сервера | <100мс | 100-200мс | >300мс |
Потеря пакетов | <0.5% | 0.5-2% | >3% |
Тестирование Качества Графики на Устройствах
Визуальное качество должно соответственно масштабироваться по уровням устройств.
Валидация Настроек Качества
Автоматизированный тест пресета качества:
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($"Качество: {benchmark.qualityLevel} - FPS: {avgFPS:F1} (цель: {benchmark.minFPS}) - Память: {peakMemory:F0}МБ (макс: {benchmark.maxMemoryMB}МБ)");
Debug.Log($"Результат: {(fpsPass && memoryPass ? "PASS" : "FAIL")}");
}
}
}
Регрессионное тестирование визуала:
Использовать инструменты сравнения скриншотов для обнаружения непреднамеренных визуальных изменений:
- Сделать базовые скриншоты для каждого уровня качества
- После изменений кода сделать новые скриншоты
- Сравнить разницу пикселей, используя инструменты сравнения изображений
- Отметить изменения, превышающие порог (например, >5% разницы пикселей)
Тестирование Аудио и Тактильной Обратной Связи
Звук и тактильная обратная связь значительно влияют на опыт игрока.
Чеклист Тестирования Аудио
Проверка реализации аудио:
- Фоновая музыка циклично воспроизводится без разрывов
- Звуковые эффекты срабатывают при правильных игровых событиях
- Приглушение аудио во время диалогов
- Настройки громкости сохраняются между сессиями
- Аудио не продолжается, когда приложение в фоне
- Пространственное позиционирование аудио (3D звук)
- Влияние аудио на производительность (использование CPU)
Тестирование тактильной обратной связи:
using UnityEngine;
public class HapticsValidator : MonoBehaviour
{
public void TestHapticFeedback()
{
// Тест легкой тактильной обратной связи
Handheld.Vibrate(); // Легкое воздействие iOS
// Проверить триггеры тактильной обратной связи:
// - Нажатие кнопки: Легкая тактильная обратная связь
// - Сбор предмета: Средняя тактильная обратная связь
// - Урон игрока: Сильная тактильная обратная связь
// - Конец игры: Паттерн вибрации
// Проверить, что тактильная обратная связь учитывает:
// - Режим беззвучности устройства (iOS)
// - Настройки предпочтений пользователя
// - Режим энергосбережения
}
}
CI/CD для Игровых Проектов
Автоматизированные пайплайны сборки и тестирования необходимы для разработки игр.
Интеграция с Unity Cloud Build
Пример конфигурации сборки:
# unity-cloud-build.yaml
targets:
android-production (как обсуждается в [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 для Тестирования Игр
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
Автоматизированная отчетность по тестам:
- Показатели прохождения юнит-тестов
- Бенчмарки производительности (FPS, память)
- Отслеживание размера сборки
- Отчеты о крашах с тестовых устройств
- Метрики покрытия кода
Заключение
Тестирование мобильных игр требует специализированной экспертизы за пределами традиционного QA. Успех требует:
- Мониторинг производительности: Непрерывное отслеживание FPS, памяти и батареи
- Тестирование сети: Измерение задержки и покрытие сценариев подключения
- Автоматизация: Unity Test Framework и тесты Automation Unreal
- Покрытие устройств: Стратегическое тестирование по уровням устройств
- Валидация монетизации: Тщательное тестирование IAP и интеграции рекламы
- Тестирование баланса: Анализ прогрессии и экономики на основе данных
- Интеграция CI/CD: Автоматизированные пайплайны сборок и тестирования
Внедрив комплексные стратегии тестирования, охватывающие производительность, функциональность, совместимость и опыт игрока, команды QA обеспечивают, что мобильные игры предоставляют стабильный и увлекательный опыт на разнообразных устройствах и сетевых условиях. Инвестиции в надежную инфраструктуру тестирования окупаются через более высокое удержание игроков, лучшие отзывы и меньше проблем после запуска.