Структуры данных для QA
Updated Jul 2026
Понимание структур данных — это не академические знания, а навык, напрямую влияющий на то, как вы пишете тестовые проверки, обрабатываете тестовые данные, валидируете ответы API и создаёте эффективные тестовые утилиты. Вам не нужно реализовывать красно-чёрное дерево, но вы должны свободно владеть списками, словарями и множествами.
Списки и массивы
Списки (Python) и массивы (JavaScript) — наиболее распространённая структура данных в автоматизации тестирования. Ответы API содержат списки элементов. Результаты тестов — это списки записей прошёл/не прошёл. Файлы логов — это списки строк.
Списки Python
# Filtering test results
results = [
{"name": "test_login", "status": "PASS", "duration": 1.2},
{"name": "test_signup", "status": "FAIL", "duration": 3.5},
{"name": "test_logout", "status": "PASS", "duration": 0.8},
{"name": "test_profile", "status": "FAIL", "duration": 2.1},
]
# List comprehension: filter failed tests
failed = [t for t in results if t["status"] == "FAIL"]
assert len(failed) == 2
# Sort by duration (slowest first)
slowest = sorted(results, key=lambda t: t["duration"], reverse=True)
assert slowest[0]["name"] == "test_signup"
# Extract just the names
names = [t["name"] for t in results]
assert "test_login" in names
# Check all tests passed (returns False if any failed)
all_passed = all(t["status"] == "PASS" for t in results)
assert not all_passed
# Check at least one test passed
any_passed = any(t["status"] == "PASS" for t in results)
assert any_passed
Массивы JavaScript/TypeScript
const results = [
{ name: "test_login", status: "PASS", duration: 1.2 },
{ name: "test_signup", status: "FAIL", duration: 3.5 },
{ name: "test_logout", status: "PASS", duration: 0.8 },
{ name: "test_profile", status: "FAIL", duration: 2.1 },
];
// Filter failed tests
const failed = results.filter(t => t.status === "FAIL");
expect(failed).toHaveLength(2);
// Sort by duration (slowest first) — note: sort mutates the array
const slowest = [...results].sort((a, b) => b.duration - a.duration);
expect(slowest[0].name).toBe("test_signup");
// Extract just the names
const names = results.map(t => t.name);
expect(names).toContain("test_login");
// Check all/any
const allPassed = results.every(t => t.status === "PASS");
const anyPassed = results.some(t => t.status === "PASS");
Типичные операции со списками в тестировании
| Операция | Python | JavaScript |
|---|---|---|
| Фильтрация | [x for x in list if cond] или filter() |
array.filter(fn) |
| Преобразование | [fn(x) for x in list] или map() |
array.map(fn) |
| Сортировка | sorted(list, key=fn) |
[...array].sort(fn) |
| Найти первый | next((x for x in list if cond), None) |
array.find(fn) |
| Проверить все | all(cond for x in list) |
array.every(fn) |
| Проверить любой | any(cond for x in list) |
array.some(fn) |
| Разворачивание | [item for sub in nested for item in sub] |
array.flat() |
| Уникальные | list(set(list)) |
[...new Set(array)] |
Словари и объекты
Словари (Python) и объекты (JavaScript) — это нативный формат для данных JSON, ответов API и конфигурации. Вы будете работать с ними постоянно.
Словари Python
# API response handling
user = {"email": "test@example.com", "role": "admin", "active": True}
assert response.json()["email"] == user["email"]
# Safely access nested data
config = {
"environments": {
"staging": {"url": "https://staging.example.com", "timeout": 30},
"production": {"url": "https://example.com", "timeout": 10}
}
}
staging_url = config.get("environments", {}).get("staging", {}).get("url")
assert staging_url == "https://staging.example.com"
# Dictionary comparison for response validation
expected = {"id": 1, "name": "Alice", "role": "admin"}
actual = response.json()
# Check expected is a subset of actual (actual may have extra fields)
for key, value in expected.items():
assert actual[key] == value, f"Mismatch on {key}: expected {value}, got {actual[key]}"
# Merge dictionaries (Python 3.9+)
default_headers = {"Content-Type": "application/json"}
auth_headers = {"Authorization": "Bearer token123"}
headers = default_headers | auth_headers
Объекты JavaScript/TypeScript
// Destructuring API responses
const { id, name, email } = response.data;
expect(id).toBeDefined();
expect(name).toBe("Alice");
// Spread operator for merging
const defaultHeaders = { "Content-Type": "application/json" };
const authHeaders = { Authorization: "Bearer token123" };
const headers = { ...defaultHeaders, ...authHeaders };
// Optional chaining for safe access
const stagingUrl = config?.environments?.staging?.url;
expect(stagingUrl).toBe("https://staging.example.com");
// Check object shape
expect(Object.keys(user)).toEqual(expect.arrayContaining(["id", "name", "email"]));
Множества
Множества обеспечивают быструю проверку принадлежности, дедупликацию и операции над множествами (объединение, пересечение, разность). Они незаменимы для валидации полей ответа и обнаружения дубликатов.
Множества Python
# Validate required fields in API response
required = {"id", "name", "email", "created_at"}
actual = set(response.json().keys())
missing = required - actual
assert not missing, f"Missing fields: {missing}"
# Check no sensitive fields are exposed
forbidden = {"password", "password_hash", "ssn", "credit_card"}
exposed = forbidden & actual # intersection
assert not exposed, f"Sensitive fields exposed: {exposed}"
# Detect duplicate IDs across paginated responses
page1_ids = {u["id"] for u in page1_response.json()["items"]}
page2_ids = {u["id"] for u in page2_response.json()["items"]}
overlap = page1_ids & page2_ids
assert not overlap, f"Duplicate IDs across pages: {overlap}"
# Verify all expected statuses are present
expected_statuses = {"pending", "processing", "completed", "failed"}
actual_statuses = {o["status"] for o in orders}
missing_statuses = expected_statuses - actual_statuses
# (This tells you which statuses are not represented in the data)
Множества JavaScript
// Deduplication
const ids = responses.map(r => r.id);
const uniqueIds = new Set(ids);
expect(uniqueIds.size).toBe(ids.length); // no duplicates
// Field validation
const required = new Set(["id", "name", "email", "created_at"]);
const actual = new Set(Object.keys(response.data));
const missing = [...required].filter(f => !actual.has(f));
expect(missing).toHaveLength(0);
Справочник по операциям над множествами
| Операция | Python | Применение |
|---|---|---|
| Объединение | a | b |
Все поля из двух ответов вместе |
| Пересечение | a & b |
Поля, присутствующие в обоих ответах |
| Разность | a - b |
Поля в a, но не в b |
| Симметрическая разность | a ^ b |
Поля в одном, но не в обоих |
| Проверка подмножества | a <= b |
Все ли обязательные поля присутствуют? |
Кортежи и именованные кортежи
Кортежи — неизменяемые последовательности, полезные для фиксированных данных, таких как пары локаторов в объектах страниц.
from selenium.webdriver.common.by import By
# Tuple for locators (cannot be accidentally modified)
EMAIL_INPUT = (By.CSS_SELECTOR, "input[name='email']")
PASSWORD_INPUT = (By.CSS_SELECTOR, "input[name='password']")
driver.find_element(*EMAIL_INPUT).send_keys("test@example.com")
# Named tuples for structured test data
from collections import namedtuple
TestUser = namedtuple("TestUser", ["email", "password", "role"])
admin = TestUser("admin@test.com", "AdminPass123!", "admin")
viewer = TestUser("viewer@test.com", "ViewerPass123!", "viewer")
assert admin.role == "admin"
Выбор правильной структуры данных
| Потребность | Используйте | Почему |
|---|---|---|
| Упорядоченная коллекция элементов | List / Array | Сохраняет порядок, допускает дубликаты |
| Поиск по ключу | Dict / Object | Поиск за O(1) по ключу |
| Уникальная коллекция, проверка принадлежности | Set | Проверка принадлежности за O(1), автоматическая дедупликация |
| Неизменяемые упорядоченные данные | Tuple | Нельзя случайно модифицировать |
| Подсчёт вхождений | collections.Counter |
Гистограмма значений |
| Упорядоченный словарь (порядок вставки) | dict (Python 3.7+) |
Гарантированный порядок вставки |
Практическое упражнение
Для API, возвращающего постраничные списки пользователей, напишите функции, которые:
- Собирают всех пользователей со всех страниц в один список
- Проверяют отсутствие дублирующихся ID между страницами
- Находят пользователей, которые есть в эндпоинте «активные пользователи», но отсутствуют в эндпоинте «все пользователи» (используйте множества)
- Группируют пользователей по роли с помощью словаря
- Сортируют пользователей по дате создания и проверяют, что они в хронологическом порядке
Ключевые выводы
- Списки/массивы: фильтрация, сортировка и преобразование тестовых данных
- Словари/объекты: обработка JSON-ответов, конфигурация, поиск по ключу
- Множества: валидация полей, обнаружение дубликатов, проверка принадлежности
- Выбирайте подходящую структуру для задачи — множества для уникальности, словари для поиска, списки для порядка
- Освойте list comprehensions (Python) и методы массивов (JavaScript) для лаконичного тестового кода