Матрица покрытия устройств
Updated Jul 2026
Принцип: выбор устройств на основе данных
Вы не можете тестировать на каждом устройстве. Ключ — это выбор на основе рисков, управляемый вашими реальными данными аналитики, а не интуицией или тем, «что лежит на столах у команды». Матрица устройств должна отвечать на вопрос: какой минимальный набор устройств покрывает максимальный процент наших пользователей?
Многоуровневая стратегия устройств
| Уровень | Критерии выбора | Целевое покрытие | Глубина тестирования |
|---|---|---|---|
| Уровень 1 (3-5 устройств) | Топ-устройства из аналитики, последняя ОС | 50-60% пользователей | Полная регрессия, каждый релиз |
| Уровень 2 (5-10 устройств) | Популярные среднего класса, одна версия назад | 25-30% пользователей | Критические пути, еженедельно |
| Уровень 3 (10-20 устройств) | Устройства длинного хвоста, самая старая поддерживаемая ОС | 10-15% пользователей | Смоук-тесты, ежемесячно |
| Крайние случаи (по необходимости) | Складные, планшеты, RTL-локали | <5% пользователей | Целевое тестирование для конкретных функций |
Построение матрицы
Процесс начинается с аналитики, а не с предположений:
# Example: building your device matrix from analytics data
import analytics
def build_device_matrix(min_coverage=0.90):
"""Select minimum device set covering 90% of users."""
devices = analytics.get_device_breakdown(days=30)
# Sort by user share descending
devices.sort(key=lambda d: d["user_share"], reverse=True)
selected = []
cumulative = 0.0
for device in devices:
selected.append(device)
cumulative += device["user_share"]
if cumulative >= min_coverage:
break
return selected
# Output example:
# [
# {"model": "iPhone 15", "os": "iOS 18", "share": 0.18},
# {"model": "iPhone 14", "os": "iOS 17", "share": 0.12},
# {"model": "Samsung Galaxy S24", "os": "Android 14", "share": 0.09},
# {"model": "iPhone 13", "os": "iOS 17", "share": 0.08},
# {"model": "Samsung Galaxy A54", "os": "Android 14", "share": 0.07},
# ... # ~12 devices to reach 90% coverage
# ]
Обогащённая матрица устройств
def build_enriched_matrix(min_coverage=0.90):
"""Build matrix with testing metadata for each device."""
base_matrix = build_device_matrix(min_coverage)
for device in base_matrix:
device["tier"] = assign_tier(device["share"])
device["test_scope"] = get_test_scope(device["tier"])
device["frequency"] = get_test_frequency(device["tier"])
device["farm_available"] = check_device_farm_availability(device["model"])
return base_matrix
def assign_tier(share):
if share >= 0.05:
return 1
elif share >= 0.02:
return 2
else:
return 3
def get_test_scope(tier):
scopes = {
1: "full_regression",
2: "critical_paths",
3: "smoke_test",
}
return scopes.get(tier, "smoke_test")
def get_test_frequency(tier):
frequencies = {
1: "every_pr",
2: "weekly",
3: "monthly",
}
return frequencies.get(tier, "monthly")
Примеры матриц устройств по типу приложения
Приложение электронной коммерции (глобальное)
| Устройство | ОС | Уровень | Почему |
|---|---|---|---|
| iPhone 15 | iOS 18 | 1 | Наибольший доход на пользователя |
| iPhone 14 | iOS 17 | 1 | Вторая по величине доля пользователей |
| Samsung Galaxy S24 | Android 14 | 1 | Топ-флагман Android |
| Samsung Galaxy A54 | Android 14 | 1 | Топ среднего класса, развивающиеся рынки |
| iPhone 13 | iOS 17 | 2 | Всё ещё широко используется |
| Google Pixel 8 | Android 14 | 2 | Референс стокового Android |
| Samsung Galaxy A14 | Android 13 | 2 | Бюджетный Android, большой объём |
| Xiaomi Redmi Note 13 | Android 14 | 2 | Популярен в Азии |
| iPhone SE (3-е поколение) | iOS 17 | 3 | Самый маленький экран, всё ещё в ходу |
| iPad (10-е поколение) | iPadOS 17 | 3 | Проверка планшетной вёрстки |
| Samsung Galaxy Z Fold5 | Android 14 | Крайний | Тестирование складных устройств |
Корпоративное B2B-приложение
| Устройство | ОС | Уровень | Почему |
|---|---|---|---|
| iPhone 15 Pro | iOS 18 | 1 | Стандартное корпоративное устройство |
| Samsung Galaxy S24 | Android 14 | 1 | Корпоративный стандарт Android |
| iPad Pro 12.9" | iPadOS 17 | 1 | Руководители используют планшеты на встречах |
| iPhone 14 | iOS 17 | 2 | Одна версия назад по политике |
| MacBook (Safari) | macOS | 2 | Доступ с десктопа |
| Windows (Chrome) | Windows | 2 | Доступ с десктопа |
Поддержание матрицы во времени
Матрицы устройств не статичны. Пересматривайте и обновляйте ежеквартально:
def quarterly_matrix_review():
"""Review and update the device matrix quarterly."""
current_matrix = load_current_matrix()
new_analytics = analytics.get_device_breakdown(days=90)
changes = []
for device in new_analytics:
# New device that crossed the Tier 2 threshold
if device["share"] >= 0.02 and device["model"] not in current_matrix:
changes.append({
"action": "ADD",
"device": device["model"],
"share": device["share"],
"reason": f"New device with {device['share']*100:.1f}% share"
})
for device in current_matrix:
# Existing device that dropped below relevance threshold
current_share = get_current_share(device, new_analytics)
if current_share < 0.01:
changes.append({
"action": "REMOVE",
"device": device["model"],
"share": current_share,
"reason": f"Share dropped to {current_share*100:.1f}%"
})
return changes
Что вызывает немедленное обновление матрицы
| Триггер | Действие |
|---|---|
| Выпуск новой мажорной версии ОС | Добавить последнюю ОС на устройства Уровня 1 |
| Выход нового флагмана | Добавить, если войдёт в топ-10 в течение 2 недель |
| Доля устройства упала ниже 1% | Перевести на Уровень 3 или удалить |
| Новый форм-фактор (складной и т.д.) | Добавить в тестирование крайних случаев |
| Выход на новый рынок (новая страна) | Получить аналитику по этому рынку, обновить матрицу |
| Баг-репорт с конкретного устройства | Временно повысить до Уровня 1 для расследования |
Маппинг матрицы на CI-пайплайн
# .github/workflows/mobile-matrix.yml
name: Mobile Test Matrix
on:
push:
branches: [main]
pull_request:
jobs:
tier-1-tests:
# Run on every PR
strategy:
matrix:
include:
- device: "iPhone 15"
os_version: "18"
platform: "ios"
- device: "Samsung Galaxy S24"
os_version: "14.0"
platform: "android"
- device: "Samsung Galaxy A54"
os_version: "14.0"
platform: "android"
steps:
- run: pytest tests/mobile/ --device="${{ matrix.device }}"
tier-2-tests:
# Run weekly on schedule
if: github.event_name == 'schedule'
strategy:
matrix:
include:
- device: "iPhone 13"
os_version: "17"
- device: "Google Pixel 8"
os_version: "14.0"
- device: "Xiaomi Redmi Note 13"
os_version: "14.0"
steps:
- run: pytest tests/mobile/ -m "critical_path" --device="${{ matrix.device }}"
tier-3-tests:
# Run monthly
if: github.event_name == 'schedule' && github.event.schedule == '0 2 1 * *'
strategy:
matrix:
include:
- device: "iPhone SE"
os_version: "17"
- device: "Samsung Galaxy A14"
os_version: "13.0"
steps:
- run: pytest tests/mobile/ -m "smoke" --device="${{ matrix.device }}"
Компромисс между покрытием и стоимостью
| Подход | Устройства | Годовая стоимость (облачная ферма) | Покрытие | Поддержка |
|---|---|---|---|---|
| Минимальный (только Уровень 1) | 3-5 | $5K-10K | 50-60% | Низкая |
| Сбалансированный (Уровень 1+2) | 8-15 | $15K-30K | 80-90% | Средняя |
| Комплексный (все уровни) | 20-30 | $30K-60K | 95%+ | Высокая |
| Исчерпывающий | 50+ | $100K+ | 99%+ | Очень высокая |
Сбалансированный подход — оптимальный выбор для большинства команд. Переход от 90% к 95% покрытия примерно удваивает стоимость и трудозатраты на поддержку. Переход от 95% к 99% удваивает их снова. Принимайте этот компромисс осознанно, исходя из вашей толерантности к риску и влияния на пользователей.