Тестирование программного обеспечения организовано в отдельные уровни, каждый из которых нацелен на различные аспекты системы и вовлекает разных членов команды. Понимание уровней тестирования помогает командам структурировать свою стратегию тестирования, распределять ответственность и обеспечивать комплексное покрытие качества от индивидуальных компонентов до полных систем.
Что Такое Уровни Тестирования?
Уровни тестирования представляют этапы в жизненном цикле разработки ПО, где происходят активности тестирования. Каждый уровень имеет специфические цели, базу тестирования, объекты тестирования и типичные дефекты для обнаружения.
Четыре Основных Уровня Тестирования
┌─────────────────────────────────────────────┐
│ User Acceptance Testing (UAT) │ ← Бизнес валидирует требования
├─────────────────────────────────────────────┤
│ System Testing │ ← Поведение полной системы
├─────────────────────────────────────────────┤
│ Integration Testing │ ← Взаимодействия компонентов
├─────────────────────────────────────────────┤
│ Unit Testing │ ← Индивидуальные компоненты
└─────────────────────────────────────────────┘
Каждый уровень строится на предыдущем, при этом дефекты в идеале обнаруживаются на самой ранней возможной стадии для минимизации стоимости и сложности. Для глубокого понимания различных подходов к тестированию через эти уровни, смотрите наше сравнение подходов к тестированию.
Unit Testing
Unit testing проверяет индивидуальные компоненты (функции, методы, классы) изолированно. Это основа пирамиды тестирования.
Цели
- Проверить, что каждая единица работает согласно дизайну
- Обнаружить логические ошибки рано в разработке
- Обеспечить безопасный рефакторинг через обнаружение регрессий
- Документировать ожидаемое поведение единиц кода
- Предоставлять быструю обратную связь разработчикам
База Тестирования
- Документы детального дизайна
- Реализация кода
- Спецификации компонентов
- Документация API
Кто Выполняет Unit Testing?
Преимущественно разработчики, часто используя Test-Driven Development (TDD):
# Пример: Unit test для сервиса аутентификации
import pytest
from auth_service import AuthService, InvalidCredentialsError
class TestAuthService:
def setup_method(self):
"""Настроить фикстуры перед каждым тестом"""
self.auth = AuthService(database="test_db")
(как обсуждается в [Entry and Exit Criteria in Software Testing: When to Start and Stop Testing](/blog/entry-exit-criteria)) self.valid_user = {
"email": "test@example.com",
"password": "SecurePass123!"
}
def test_successful_authentication(self):
"""Тест что валидные учётные данные возвращают auth token"""
token = self.auth.authenticate(
self.valid_user["email"],
self.valid_user["password"]
)
assert token is not None
assert len(token) == 64 # Длина JWT token
assert self.auth.is_token_valid(token) is True
def test_invalid_password_raises_error(self):
"""Тест что невалидный пароль генерирует соответствующую ошибку"""
with pytest.raises(InvalidCredentialsError) as exc_info:
self.auth.authenticate(
self.valid_user["email"],
"WrongPassword"
)
assert "Invalid credentials" in str(exc_info.value)
def test_nonexistent_user_raises_error(self):
"""Тест что несуществующий пользователь генерирует ошибку"""
with pytest.raises(InvalidCredentialsError):
self.auth.authenticate(
"nonexistent@example.com",
"anypassword"
)
def test_account_lockout_after_failed_attempts(self):
"""Тест что аккаунт блокируется после 5 неудачных попыток входа"""
# Попытка 5 неудачных входов
for _ in range(5):
with pytest.raises(InvalidCredentialsError):
self.auth.authenticate(
self.valid_user["email"],
"WrongPassword"
)
# 6-я попытка должна вызвать AccountLockedError
from auth_service import AccountLockedError
with pytest.raises(AccountLockedError):
self.auth.authenticate(
self.valid_user["email"],
self.valid_user["password"] # Даже с правильным паролем
)
def test_token_expiration(self):
"""Тест что токены истекают после настроенного времени"""
import time
token = self.auth.authenticate(
self.valid_user["email"],
self.valid_user["password"]
)
# Имитировать прохождение времени (в реальном коде использовать библиотеку time mocking)
self.auth._set_time_offset(3600) # +1 час
assert self.auth.is_token_valid(token) is False
Типичные Найденные Дефекты
- Неправильные вычисления или логика
- Ошибки граничных значений
- Исключения нулевого указателя
- Неправильные типы переменных
- Ошибки циклов (off-by-one, бесконечные циклы)
- Неправильная обработка ошибок
Лучшие Практики
- Следовать паттерну AAA: Arrange, Act, Assert
- Тестировать одну вещь за тест: Каждый тест должен проверять одно поведение
- Использовать описательные имена тестов:
test_account_locks_after_5_failed_attempts
- Изолировать зависимости: Использовать mocks/stubs для внешних зависимостей
- Стремиться к высокому покрытию: Минимум 70-80%, критический код 100%
- Быстрое выполнение: Unit tests должны выполняться за миллисекунды
Integration Testing
Integration (как обсуждается в Dynamic Testing: Testing in Action) testing проверяет взаимодействия между интегрированными компонентами или системами. Он обнаруживает дефекты интерфейса, которые пропускают unit tests.
Цели
- Проверить интерфейсы между компонентами
- Протестировать поток данных между модулями
- Валидировать контракты API
- Обнаружить баги интеграции рано
- Тестировать сценарии взаимодействия компонентов
База Тестирования
- Документы дизайна программного обеспечения и системы
- Диаграммы архитектуры
- Спецификации API
- Определения интерфейсов
- Описания use case
Подходы к Интеграции
Интеграция Big Bang:
Все компоненты интегрированы одновременно → Тестировать всё сразу
Плюсы: Быстро настроить
Минусы: Трудно изолировать дефекты, рискованно
Инкрементальная Интеграция:
Компоненты интегрированы и протестированы инкрементально
Top-Down: Начать с высокоуровневых модулей, stub нижние уровни
Bottom-Up: Начать с низкоуровневых модулей, создать драйверы для высоких уровней
Sandwich: Комбинация top-down и bottom-up
Пример: API Integration Testing
// Пример: Тестирование интеграции между аутентификацией и сервисом пользователя
const request = require('supertest');
const app = require('../app');
describe('Интеграция Аутентификации и Сервиса Пользователя', () => {
let authToken;
let userId;
beforeAll(async () => {
// Настроить тестовую базу данных
await setupTestDatabase() (как обсуждается в [Grey Box Testing: Best of Both Worlds](/blog/grey-box-testing));
});
afterAll(async () => {
// Очистить тестовую базу данных
await cleanupTestDatabase();
});
test('Регистрация пользователя создаёт пользователя и возвращает auth token', async () => {
const newUser = {
email: 'integration@test.com',
password: 'SecurePass123!',
name: 'Integration Test User'
};
const response = await request(app)
.post('/api/auth/register')
.send(newUser)
.expect(201);
// Проверить структуру ответа
expect(response.body).toHaveProperty('token');
expect(response.body).toHaveProperty('user');
expect(response.body.user.email).toBe(newUser.email);
// Сохранить для последующих тестов
authToken = response.body.token;
userId = response.body.user.id;
});
test('Аутентифицированный пользователь может получить доступ к эндпоинту профиля', async () => {
const response = await request(app)
.get(`/api/users/${userId}/profile`)
.set('Authorization', `Bearer ${authToken}`)
.expect(200);
expect(response.body.email).toBe('integration@test.com');
expect(response.body.name).toBe('Integration Test User');
});
test('Неаутентифицированный запрос к профилю возвращает 401', async () => {
await request(app)
.get(`/api/users/${userId}/profile`)
.expect(401);
});
test('Невалидный токен возвращает 403', async () => {
await request(app)
.get(`/api/users/${userId}/profile`)
.set('Authorization', 'Bearer invalid_token_here')
.expect(403);
});
test('Пользователь может обновить профиль с валидным auth token', async () => {
const updates = {
name: 'Updated Name',
bio: 'Integration testing is awesome'
};
const response = await request(app)
.patch(`/api/users/${userId}/profile`)
.set('Authorization', `Bearer ${authToken}`)
.send(updates)
.expect(200);
expect(response.body.name).toBe('Updated Name');
expect(response.body.bio).toBe('Integration testing is awesome');
});
test('Logout инвалидирует auth token', async () => {
// Logout
await request(app)
.post('/api/auth/logout')
.set('Authorization', `Bearer ${authToken}`)
.expect(200);
// Попытка доступа к профилю с инвалидированным токеном
await request(app)
.get(`/api/users/${userId}/profile`)
.set('Authorization', `Bearer ${authToken}`)
.expect(401);
});
});
Типичные Найденные Дефекты
- Неправильные параметры вызовов API
- Несоответствия формата данных между компонентами
- Отсутствующая или неправильная обработка ошибок между сервисами
- Проблемы таймингов (условия гонки, дедлоки)
- Неправильные предположения о поведении компонентов
- Проблемы подключения к базе данных
- Сбои коммуникации очереди сообщений
Лучшие Практики
- Тестировать реалистичные сценарии: Использовать реальные потоки интеграции
- Использовать тестовые базы данных: Изолировать от продакшн данных
- Тестировать условия ошибок: Сбои сети, таймауты, невалидные ответы
- Поддерживать тестовые данные: Создавать переиспользуемые фикстуры
- Запускать в CI/CD: Автоматизировать выполнение на каждой сборке
- Contract testing: Проверять API контракты между сервисами
System Testing
System testing валидирует полную интегрированную систему против заданных требований. Он тестирует end-to-end сценарии с перспективы пользователя.
Цели
- Проверить, что система соответствует функциональным требованиям
- Валидировать поведение системы в реалистичных окружениях
- Тестировать нефункциональные требования (производительность, безопасность, юзабилити)
- Проверить правильную интеграцию системы с внешними системами
- Валидировать полные пользовательские рабочие потоки
База Тестирования
- Спецификации требований системы и ПО
- Use cases и user stories
- Документы архитектуры системы
- Описания бизнес-процессов
- Пользовательская документация
Кто Выполняет System Testing?
Независимая тестовая команда или QA-инженеры, отдельные от команды разработки для обеспечения объективности.
Типы System Testing
Тип | Фокус | Пример |
---|---|---|
Функциональный | Функции работают согласно спецификации | Процесс оформления заказа e-commerce |
Производительность | Время ответа, пропускная способность | Загрузка 1000 одновременных пользователей |
Безопасность | Уязвимости, контроль доступа | SQL injection, XSS атаки |
Юзабилити | Пользовательский опыт, лёгкость использования | Навигация, валидация форм |
Совместимость | Работает в разных окружениях | Кросс-браузерность, мобильные устройства |
Восстановление | Система восстанавливается после сбоев | Восстановление после краха БД |
Установка | Развёртывание и настройка | Чистая установка, сценарии обновления |
Пример: Сценарии System Test
# Функциональный System Test: Поток Покупки E-commerce
Feature: Полный рабочий процесс покупки
Как клиент
Я хочу покупать продукты
Чтобы получить их по своему адресу
Background:
Given система e-commerce работает
And тестовые продукты существуют в инвентаре
And тестовая учётная запись пользователя "systemtest@example.com" существует
Scenario: Успешная покупка продукта с кредитной картой
Given я аутентифицирован как "systemtest@example.com"
When я ищу "wireless headphones"
And выбираю "Sony WH-1000XM4" из результатов
And нажимаю "Добавить в Корзину"
And перехожу к оформлению заказа
And ввожу адрес доставки:
| Поле | Значение |
| Улица | 123 Test St |
| Город | San Francisco |
| Штат | CA |
| Индекс | 94105 |
And выбираю "Кредитная Карта" как способ оплаты
And ввожу валидные данные кредитной карты
And подтверждаю заказ
Then я должен увидеть сообщение "Заказ Подтверждён"
And я должен получить email подтверждения заказа в течение 2 минут
And статус заказа должен быть "Обрабатывается" в моей учётной записи
And инвентарь должен уменьшиться на 1 для "Sony WH-1000XM4"
And платёж должен быть обработан на сумму $349.99
Scenario: Обработка товара вне склада
Given продукт "Limited Edition Watch" имеет 0 в инвентаре
When я пытаюсь добавить его в корзину
Then я должен увидеть уведомление "Нет в Наличии"
And кнопка "Добавить в Корзину" должна быть отключена
And я должен увидеть опцию "Уведомить меня когда будет доступно"
Scenario: Невалидная информация о платеже
Given у меня есть товары в корзине
When я перехожу к оформлению заказа
And ввожу невалидный номер кредитной карты "1234 5678 9012 3456"
And подтверждаю заказ
Then я должен увидеть ошибку "Неверная информация о платеже"
And заказ не должен быть создан
And инвентарь не должен уменьшиться
Пример Performance Testing
# Пример: Load testing для валидации производительности системы
from locust import HttpUser, task, between
class EcommerceUser(HttpUser):
wait_time = between(1, 3) # Ждать 1-3 секунды между запросами
def on_start(self):
"""Login когда пользователь начинает"""
response = self.client.post("/api/auth/login", json={
"email": "loadtest@example.com",
"password": "TestPass123!"
})
self.token = response.json()["token"]
@task(3)
def browse_products(self):
"""Просматривать продукты (высокая частота)"""
self.client.get("/api/products", headers={
"Authorization": f"Bearer {self.token}"
})
@task(2)
def view_product_detail(self):
"""Смотреть конкретный продукт (средняя частота)"""
self.client.get("/api/products/12345", headers={
"Authorization": f"Bearer {self.token}"
})
@task(1)
def add_to_cart(self):
"""Добавить продукт в корзину (меньшая частота)"""
self.client.post("/api/cart/items", json={
"productId": "12345",
"quantity": 1
}, headers={
"Authorization": f"Bearer {self.token}"
})
@task(1)
def view_cart(self):
"""Просмотреть корзину покупок"""
self.client.get("/api/cart", headers={
"Authorization": f"Bearer {self.token}"
})
# Запустить с: locust -f system_load_test.py --users 1000 --spawn-rate 50
# Тестирует систему с 1000 одновременных пользователей, увеличивая 50 пользователей в секунду
Типичные Найденные Дефекты
- Функциональные требования не выполнены
- Ошибки бизнес-логики
- Сбои workflow end-to-end
- Узкие места производительности
- Уязвимости безопасности
- Проблемы совместимости между браузерами/устройствами
- Неправильные сообщения об ошибках или обработка
- Проблемы целостности данных
Лучшие Практики
- Тестировать в продакшн-подобном окружении: Соответствовать архитектуре, объёмам данных
- Использовать реалистичные тестовые данные: Представлять реальные паттерны использования
- Автоматизировать регрессионные тесты: Основная функциональность должна быть автоматизирована
- Тестировать нефункциональные требования: Производительность, безопасность, масштабируемость
- Документировать результаты тестирования: Всесторонняя отчётность для заинтересованных сторон
- Приоритизировать по риску: Фокусироваться сначала на критических бизнес-потоках
User Acceptance Testing (UAT)
UAT валидирует, что система соответствует бизнес-требованиям и готова к развёртыванию. Реальные пользователи тестируют в реалистичных сценариях.
Цели
- Проверить, что система соответствует бизнес-потребностям
- Валидировать юзабилити с перспективы конечного пользователя
- Убедиться, что система готова к продакшн развёртыванию
- Обрести уверенность заинтересованных сторон
- Выявить пробелы между требованиями и реализацией
База Тестирования
- Бизнес-требования и процессы
- Пользовательские требования и user stories
- Пользовательские руководства и материалы для обучения
- Рабочие потоки бизнес-процессов
- Критерии приемки
Кто Выполняет UAT?
Бизнес-пользователи, product owners, заинтересованные стороны—люди, которые на самом деле будут использовать систему.
Типы UAT
Alpha Testing:
- Выполняется внутренним персоналом (не командой разработки)
- Проводится в окружении разработки
- Ранняя обратная связь перед внешними пользователями
Beta Testing:
- Выполняется реальными конечными пользователями
- Проводится в продакшн или близком к продакшн окружении
- Сценарии реального использования
- Собранная обратная связь для финальных улучшений
Contract Acceptance Testing:
- Валидирует соответствие системы спецификациям контракта
- Часто юридически обязывающее
- Выполняется перед оплатой/поставкой
Operational Acceptance Testing:
- Валидирует готовность системы к эксплуатации
- Тестирует backup/восстановление, поддерживаемость, безопасность
- Часто выполняется командой эксплуатации
Пример: UAT Test Case
## UAT Test Case: Генерация Месячного Финансового Отчёта
**Test ID:** UAT-FIN-001
**Feature:** Финансовые Отчёты
**Приоритет:** Высокий
**Тестировщик:** Jane Smith (Менеджер по Финансам)
**Дата:** 2025-10-02
### Бизнес-Требование
Менеджерам по финансам необходимо генерировать всесторонние месячные финансовые отчёты,
которые обобщают доходы, расходы и маржу прибыли по департаментам.
### Предусловия
- Пользователь имеет роль Менеджера по Финансам
- Финансовые данные существуют для Сентября 2025
- Пользователь аутентифицирован в системе
### Шаги Тестирования
1. Перейти к Отчёты → Финансовые → Месячная Сводка
- **Ожидается:** Страница Месячной Сводки загружается в течение 3 секунд
- **Факт:** _______________
- **Пройдено/Провалено:** ___________
2. Выбрать "Сентябрь 2025" из выпадающего списка месяца
- **Ожидается:** Месяц выбран, форма обновляется
- **Факт:** _______________
- **Пройдено/Провалено:** ___________
3. Выбрать "Все Департаменты" или конкретный департамент
- **Ожидается:** Выбор департамента доступен
- **Факт:** _______________
- **Пройдено/Провалено:** ___________
4. Нажать кнопку "Сгенерировать Отчёт"
- **Ожидается:** Отчёт генерируется в течение 10 секунд, показывается индикатор прогресса
- **Факт:** _______________
- **Пройдено/Провалено:** ___________
5. Проверить содержимое отчёта на точность
- **Ожидается:** Отчёт включает:
- Общий доход по департаментам
- Общие расходы по категориям
- Расчёты маржи прибыли
- Сравнение месяц к месяцу
- Визуальные графики (тренд дохода, разбивка расходов)
- **Факт:** _______________
- **Пройдено/Провалено:** ___________
6. Проверить, что числа отчёта соответствуют исходным данным
- **Ожидается:** Вручную проверить, что 3 примера транзакций отображаются правильно
- **Факт:** _______________
- **Пройдено/Провалено:** ___________
7. Экспортировать отчёт как PDF
- **Ожидается:** PDF скачивается, сохраняет форматирование, включает все данные
- **Факт:** _______________
- **Пройдено/Провалено:** ___________
8. Экспортировать отчёт как Excel
- **Ожидается:** Excel скачивается, данные редактируемы, формулы включены
- **Факт:** _______________
- **Пройдено/Провалено:** ___________
### Критерии Бизнес Приемки
- [ ] Отчёт точно отражает финансовые данные
- [ ] Отчёт генерируется в приемлемое время (< 10 секунд)
- [ ] Формат отчёта соответствует бизнес-стандартам
- [ ] Функциональность экспорта работает для PDF и Excel
- [ ] Отчёт понятен без технических знаний
### Комментарии/Issues
_____________________________________________________________________
_____________________________________________________________________
### Общий Результат: ПРОЙДЕНО / ПРОВАЛЕНО / УСЛОВНО ПРОЙДЕНО
**Подписано:** _____________________ **Дата:** __________
Типичные Найденные Дефекты
- Требования неверно поняты командой разработки
- Проблемы юзабилити (запутанный UI, непонятные сообщения)
- Отсутствующие бизнес-правила или граничные случаи
- Неправильные вычисления или бизнес-логика
- Отчёты не соответствуют ожидаемому формату
- Workflow не соответствует реальному бизнес-процессу
- Проблемы производительности с реалистичными объёмами данных
Лучшие Практики
- Вовлекать реальных пользователей: Не посредников или QA, притворяющихся пользователями
- Использовать реалистичные данные: Маскировать продакшн данные при необходимости
- Документировать ясно: Использовать нетехнический язык
- Планировать достаточное время: Не спешить с фазой UAT
- Определять чёткие критерии приемки: Бинарное пройдено/провалено на требование
- Обеспечивать обучение: Помогать пользователям понимать, что тестировать
- Собирать обратную связь: Помимо пройдено/провалено, собирать предложения по улучшению
Сравнение Уровней Тестирования
Аспект | Unit | Integration | System | UAT |
---|---|---|---|---|
Выполняется | Разработчики | Разработчики/QA | Команда QA | Бизнес-Пользователи |
Фокус | Индивидуальные компоненты | Взаимодействия компонентов | Полная система | Бизнес-требования |
Окружение | Машина разработчика | Тестовое окружение | Staging/Test | Подобное продакшн |
База Тестирования | Код, docs дизайна | Specs интерфейса | Требования | Бизнес-потребности |
Автоматизация | Высоко автоматизировано | В основном автоматизировано | Частично автоматизировано | В основном ручное |
Скорость Выполнения | Миллисекунды | Секунды | Минуты | Часы/Дни |
Когда | Во время кодирования | После unit testing | После integration | Перед релизом |
Типичные Дефекты | Логические ошибки | Проблемы интерфейса | Баги end-to-end | Пробелы требований |
Стратегия Уровней Тестирования
Стоимость Дефектов по Уровням
Дефект найден на: | Стоимость исправления
-------------------|----------------------
Unit Testing | $ (1x)
Integration Testing| $$ (10x)
System Testing | $$$ (100x)
UAT | $$$$ (1000x)
Продакшн | $$$$$ (10,000x)
Ключевой Принцип: Находить дефекты как можно раньше.
Распределение Тестового Покрытия
Следовать пирамиде тестирования:
/\
/ \ UAT (Ручное)
/ 10%\ - Критические пользовательские пути
/------\ - Валидация бизнеса
/ \
/ 30% \ System Tests (В Основном Автоматизированы)
/ Tests \ - Сценарии end-to-end
/--------------\- Нефункциональное тестирование
/ \
/ 60% Unit \ Unit & Integration Tests (Полностью Автоматизированы)
/ & Integration \- Быстрые, надёжные, обширное покрытие
/____Tests_________\
Заключение
Понимание уровней тестирования позволяет командам:
- Структурировать активности тестирования логически в течение жизненного цикла разработки
- Распределять ответственность соответствующим образом между разработчиками, QA и бизнес-пользователями
- Оптимизировать обнаружение дефектов, обнаруживая проблемы на самой ранней и дешёвой стадии
- Балансировать ручное и автоматизированное тестирование на разных уровнях
- Обеспечивать всестороннее покрытие от индивидуальных компонентов до полных бизнес-рабочих потоков
Каждый уровень тестирования служит отдельной цели. Успех достигается выполнением всех уровней соответствующим образом, с надлежащим тестовым покрытием, чёткими ответственностями и акцентом на раннее обнаружение дефектов через unit и integration testing при валидации бизнес-ценности через system testing и UAT. Для получения дополнительной информации о функциональном тестировании на этих уровнях, смотрите наше полное руководство по функциональному тестированию.