Modern QA2026Структуры данных для QA
Join

Course12 Programming for QA

Foundations · Chapter 12

Структуры данных для 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, возвращающего постраничные списки пользователей, напишите функции, которые:

  1. Собирают всех пользователей со всех страниц в один список
  2. Проверяют отсутствие дублирующихся ID между страницами
  3. Находят пользователей, которые есть в эндпоинте «активные пользователи», но отсутствуют в эндпоинте «все пользователи» (используйте множества)
  4. Группируют пользователей по роли с помощью словаря
  5. Сортируют пользователей по дате создания и проверяют, что они в хронологическом порядке

Ключевые выводы

  • Списки/массивы: фильтрация, сортировка и преобразование тестовых данных
  • Словари/объекты: обработка JSON-ответов, конфигурация, поиск по ключу
  • Множества: валидация полей, обнаружение дубликатов, проверка принадлежности
  • Выбирайте подходящую структуру для задачи — множества для уникальности, словари для поиска, списки для порядка
  • Освойте list comprehensions (Python) и методы массивов (JavaScript) для лаконичного тестового кода