Как можно протестировать требование?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Как протестировать требование
Тестирование требования — это процесс проверки, что реализованная функциональность соответствует исходному требованию. Это не просто проверка на ошибки, а подтверждение того, что система делает именно то, что нужно бизнесу. Это ключевая задача системного аналитика и QA команды.
Основной подход: Acceptance Criteria
Перед тестированием требования нужно определить критерии приёмки (Acceptance Criteria). Это конкретные, проверяемые условия, которые должны быть выполнены.
Пример:
Требование: "Пользователь должен иметь возможность отфильтровать товары по цене"
Акцептанс критерии:
- AC1: При выборе диапазона цены от 100 до 500 показываются только товары в этом диапазоне
- AC2: Фильтр работает при первой загрузке страницы
- AC3: При изменении фильтра список обновляется в реальном времени
- AC4: При очистке фильтра показываются все товары
- AC5: Фильтр сохраняется при обновлении страницы (URL параметры)
1. Модульное тестирование (Unit Testing)
Что тестировать: Отдельные компоненты и функции, которые реализуют требование.
Пример: Фильтрация товаров
import pytest
from app.services import ProductService
class TestProductFilter:
def test_filter_by_price_range(self):
"""AC1: Фильтр работает по диапазону цены"""
service = ProductService()
# Arrange
products = [
{"id": 1, "name": "Товар 1", "price": 100},
{"id": 2, "name": "Товар 2", "price": 300},
{"id": 3, "name": "Товар 3", "price": 600},
]
# Act
filtered = service.filter_by_price(products, min_price=100, max_price=500)
# Assert
assert len(filtered) == 2
assert filtered[0]["id"] == 1
assert filtered[1]["id"] == 2
def test_filter_empty_result(self):
"""AC: Фильтр может вернуть пустой результат"""
service = ProductService()
products = [{"id": 1, "price": 100}]
filtered = service.filter_by_price(products, min_price=500, max_price=1000)
assert len(filtered) == 0
def test_filter_all_results_with_empty_filter(self):
"""AC4: Без фильтра показываются все товары"""
service = ProductService()
products = [
{"id": 1, "price": 100},
{"id": 2, "price": 300},
]
filtered = service.filter_by_price(products, min_price=None, max_price=None)
assert len(filtered) == 2
2. Интеграционное тестирование (Integration Testing)
Что тестировать: Взаимодействие компонентов при реализации требования.
Пример: Фильтрация + сохранение в БД
import pytest
from app import db, create_app
from app.models import Product
@pytest.fixture
def app():
app = create_app('testing')
with app.app_context():
db.create_all()
yield app
db.session.remove()
db.drop_all()
def test_filter_products_from_database(app):
"""AC1: Фильтр работает с реальными данными из БД"""
with app.app_context():
# Arrange
db.session.add(Product(name="Товар 1", price=100))
db.session.add(Product(name="Товар 2", price=300))
db.session.add(Product(name="Товар 3", price=600))
db.session.commit()
# Act
products = Product.query.filter(
Product.price >= 100,
Product.price <= 500
).all()
# Assert
assert len(products) == 2
assert products[0].name == "Товар 1"
def test_filter_preserves_in_url(app):
"""AC5: Фильтр сохраняется в URL параметрах"""
client = app.test_client()
# Act
response = client.get('/products?min_price=100&max_price=500')
# Assert
assert response.status_code == 200
assert 'min_price=100' in response.request.url
assert 'max_price=500' in response.request.url
3. End-to-End тестирование (E2E Testing)
Что тестировать: Весь путь пользователя от начала до конца.
Пример: Полный сценарий фильтрации (Playwright)
import pytest
from playwright.sync_api import sync_playwright
def test_filter_products_e2e():
"""AC: Пользователь может отфильтровать товары по цене"""
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
# Arrange
page.goto('http://localhost:3000/products')
# Act: Установить фильтр
page.fill('input[placeholder="Min price"]', '100')
page.fill('input[placeholder="Max price"]', '500')
page.click('button:has-text("Apply Filter")')
# Assert: Проверить результаты
products = page.query_selector_all('.product-item')
assert len(products) == 2
prices = []
for product in products:
price_text = product.query_selector('.price').text_content()
prices.append(int(price_text.replace('$', '')))
assert all(100 <= p <= 500 for p in prices)
# Act: Обновить страницу
page.reload()
# Assert: AC5 - фильтр сохраняется
products = page.query_selector_all('.product-item')
assert len(products) == 2
# Cleanup
browser.close()
4. API тестирование
Что тестировать: REST API endpoints, которые реализуют требование.
Пример: Фильтрация через API
import pytest
from httpx import Client
def test_filter_products_api():
"""AC1: API возвращает отфильтрованные товары"""
client = Client(base_url='http://localhost:8000')
# Act
response = client.get('/api/v1/products', params={
'min_price': 100,
'max_price': 500
})
# Assert
assert response.status_code == 200
data = response.json()
assert len(data['items']) == 2
for product in data['items']:
assert 100 <= product['price'] <= 500
def test_filter_with_invalid_range():
"""AC: API обрабатывает неправильный диапазон"""
client = Client(base_url='http://localhost:8000')
# Act: min > max
response = client.get('/api/v1/products', params={
'min_price': 500,
'max_price': 100
})
# Assert
assert response.status_code == 400 # или 200 с пустым результатом
# Зависит от требования обработки ошибок
5. Тестирование граничных случаев (Edge Cases)
Что тестировать: Нестандартные ситуации.
def test_filter_edge_cases():
service = ProductService()
products = [
{"id": 1, "price": 0},
{"id": 2, "price": 100},
{"id": 3, "price": 999999},
]
# Граница: цена 0
assert service.filter_by_price(products, 0, 0) == [{"id": 1, "price": 0}]
# Очень большая цена
assert len(service.filter_by_price(products, 100, 999999)) == 2
# Отрицательная цена (должна быть обработана)
# В зависимости от требования
# None значения
assert len(service.filter_by_price(products, None, 100)) == 2
6. Performance тестирование
Что тестировать: Требование работает быстро даже при большом количестве данных.
Пример: Фильтрация 1 млн товаров
import time
import pytest
def test_filter_performance(benchmark):
"""AC3: Фильтр работает в реальном времени (< 500ms)"""
service = ProductService()
# Создать большой список
products = [{"id": i, "price": i % 1000} for i in range(1_000_000)]
# Benchmark
result = benchmark(lambda: service.filter_by_price(products, 100, 500))
# Assert
assert len(result) > 0
# benchmark автоматически проверит время
7. Security тестирование
Что тестировать: Требование не создаёт уязвимостей.
Пример: SQL Injection
def test_filter_sql_injection_prevention():
"""AC: Фильтр безопасен от SQL injection"""
client = Client(base_url='http://localhost:8000')
# Попытка SQL injection
response = client.get('/api/v1/products', params={
'min_price': "100; DROP TABLE products;",
'max_price': 500
})
# Assert
assert response.status_code in [400, 422] # Ошибка валидации
# Проверить, что БД не повреждена
response = client.get('/api/v1/products')
assert response.status_code == 200
8. UAT (User Acceptance Testing)
Что тестировать: Реальный пользователь согласен, что требование выполнено.
Процесс:
- Подготовить тестовую среду с реальными данными
- Дать доступ stakeholders
- Предоставить чек-лист (основан на AC)
- Собрать feedback
- Отправить на доработку или приём
Чек-лист:
- AC1: Фильтр по цене от 100 до 500 работает
- AC2: При первой загрузке фильтр применяется
- AC3: При изменении чисел список обновляется мгновенно
- AC4: При очистке фильтра показываются все товары
- AC5: При перезагрузке страницы фильтр сохраняется
9. Регрессионное тестирование
Что тестировать: Новое требование не сломало старую функциональность.
def test_filter_does_not_break_sorting():
"""Фильтр + сортировка должны работать вместе"""
service = ProductService()
products = [
{"id": 1, "price": 500},
{"id": 2, "price": 100},
{"id": 3, "price": 300},
]
# Применить фильтр И сортировку
filtered = service.filter_by_price(products, 100, 500)
sorted_products = sorted(filtered, key=lambda x: x['price'])
# Assert
assert sorted_products[0]['price'] == 100
assert sorted_products[1]['price'] == 300
assert sorted_products[2]['price'] == 500
Матрица тестирования требования
| Тип тестирования | Что проверяет | Кто проводит | Когда |
|---|---|---|---|
| Unit | Функции работают | Разработчик | Разработка |
| Integration | Компоненты взаимодействуют | QA | После разработки |
| E2E | Путь пользователя | QA | Перед UAT |
| API | REST endpoints | QA автоматизация | Непрерывно |
| Edge Cases | Граничные случаи | QA | Пред-тестирование |
| Performance | Скорость | QA нагрузочное | Пред-production |
| Security | Безопасность | Security team | Пред-production |
| UAT | Соответствие бизнесу | Stakeholders | Перед релизом |
| Regression | Нет деградации | Автоматизация | После каждого изменения |
Инструменты для тестирования
Unit & Integration:
- pytest (Python)
- Jest (JavaScript)
- JUnit (Java)
E2E:
- Playwright
- Cypress
- Selenium
API:
- Postman
- REST Assured
- httpx
Performance:
- JMeter
- Locust
- K6
UAT:
- TestRail
- Zephyr
- HP Quality Center
Лучшие практики
- Пишите тесты ДО разработки (TDD) — сначала test, потом код
- Базируйте тесты на AC — каждый AC = минимум один тест
- Автоматизируйте всё, что можно — особенно регрессию
- Тестируйте граничные случаи — не только "happy path"
- Проверяйте performance — требование может быть медленным
- Включите UAT — реальный пользователь = окончательная проверка
- Документируйте результаты — Traceability Matrix
Трассируемость требований
Лучше всего создать Requirements Traceability Matrix (RTM):
| Требование | AC1 | AC2 | AC3 | Unit test | E2E test | UAT | Статус |
|---|---|---|---|---|---|---|---|
| Фильтр цена | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | Готово |
Это показывает, что каждое требование полностью протестировано.
Вывод
Протестировать требование — значит:
- Определить acceptance criteria
- Написать unit тесты
- Написать интеграционные тесты
- Написать E2E тесты
- Провести UAT с пользователями
- Убедиться, что регрессии нет
- Документировать результаты
Только тогда можно быть уверенным, что требование действительно выполнено.