Правильно настроенное тестовое окружение критично для надёжного и повторяемого тестирования. Это руководство охватывает всё от базовой настройки до продвинутых стратегий контейнеризации, обеспечивая точное отражение продакшна в вашем тестовом окружении при сохранении изоляции и управляемости.
Что такое Тестовое Окружение?
Тестовое окружение — это настройка программного обеспечения и аппаратного обеспечения, где команды тестирования выполняют тестовые случаи. Оно имитирует условия продакшна, обеспечивая изоляцию для безопасного тестирования без влияния на живые системы.
Ключевые Компоненты
Инфраструктура:
- Серверы (физические или виртуальные)
- Конфигурация сети
- Системы хранения
- Балансировщики нагрузки
Программное обеспечение:
- Операционные системы
- Серверы приложений
- Базы данных
- Интеграции с третьими сторонами
- Инструменты мониторинга
Данные:
- Тестовые базы данных
- Наборы образцов данных
- Конфигурационные файлы
- Переменные окружения
Доступ и Безопасность:
- Учётные записи пользователей
- Разрешения
- API ключи
- SSL сертификаты
Типы Тестовых Окружений
1. Окружение Разработки (DEV)
Используется разработчиками для кодирования и начального тестирования.
# dev-environment.yml
environment: development
database:
host: localhost
port: 5432
name: myapp_dev
user: dev_user
cache:
provider: redis
host: localhost
port: 6379
api:
base_url: http://localhost:3000
debug_mode: true
log_level: DEBUG
features:
email_service: mock # Не отправлять реальные письма
payment_gateway: sandbox
cdn: local_storage
monitoring:
enabled: false # Без мониторинга в dev
2. Окружение Тестирования/QA
Выделенное окружение для тестирования командой QA.
# qa-environment.yml
environment: qa
database (как обсуждается в [Continuous Testing in DevOps: Quality Gates and CI/CD Integration](/blog/continuous-testing-devops)):
host: qa-db.internal.company.com
port: 5432
name: myapp_qa
user: qa_user
pool_size: 10
cache:
provider: redis
(как обсуждается в [Grey Box Testing: Best of Both Worlds](/blog/grey-box-testing)) host: qa-redis.internal.company.com
port: 6379
cluster: true
api:
base_url: https://qa.myapp.com
debug_mode: false
log_level: INFO
features:
email_service: mailtrap # Сервис тестирования email
payment_gateway: stripe_test
cdn: qa_cdn
monitoring (как обсуждается в [Risk-Based Testing: Prioritizing Test Efforts for Maximum Impact](/blog/risk-based-testing)):
enabled: true
service: datadog
alerts: qa-team@company.com
performance:
rate_limit: 1000_per_minute
max_connections: 100
test_data:
auto_refresh: daily
anonymized: true
3. Окружение Staging
Предпродакшн окружение, которое отражает продакшн.
4. Продакшн Окружение
Живое окружение, обслуживающее реальных пользователей.
Шаги Настройки Тестового Окружения
Шаг 1: Провизионирование Инфраструктуры
# Инфраструктура как Код (Terraform)
# terraform/qa-environment.tf
# Конфигурация VPC
resource "aws_vpc" "qa_vpc" {
cidr_block = "10.0.0.0/16"
tags = {
Name = "qa-vpc"
Environment = "qa"
}
}
# Подсеть
resource "aws_subnet" "qa_subnet" {
vpc_id = aws_vpc.qa_vpc.id
cidr_block = "10.0.1.0/24"
tags = {
Name = "qa-subnet"
}
}
# Группа Безопасности
resource "aws_security_group" "qa_sg" {
name = "qa-security-group"
description = "Группа безопасности окружения QA"
vpc_id = aws_vpc.qa_vpc.id
# Разрешить HTTP откуда угодно
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
# Разрешить HTTPS откуда угодно
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
# Разрешить SSH только из сети компании
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["203.0.113.0/24"] # IP диапазон компании
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
Шаг 2: Развёртывание Приложения
# Docker Compose для Окружения QA
# docker-compose.qa.yml
version: '3.8'
services:
# Сервер Приложения
app:
image: myapp:qa-latest
container_name: qa-app
ports:
- "3000:3000"
environment:
- NODE_ENV=qa
- DATABASE_URL=postgresql://qa_user:${DB_PASSWORD}@qa-db:5432/myapp_qa
- REDIS_URL=redis://qa-redis:6379
- API_KEY=${API_KEY}
- SECRET_KEY=${SECRET_KEY}
depends_on:
- db
- redis
networks:
- qa-network
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
# База Данных
db:
image: postgres:13
container_name: qa-db
environment:
- POSTGRES_DB=myapp_qa
- POSTGRES_USER=qa_user
- POSTGRES_PASSWORD=${DB_PASSWORD}
volumes:
- qa-db-data:/var/lib/postgresql/data
- ./init-scripts:/docker-entrypoint-initdb.d
ports:
- "5432:5432"
networks:
- qa-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U qa_user"]
interval: 10s
timeout: 5s
retries: 5
# Redis Cache
redis:
image: redis:6-alpine
container_name: qa-redis
ports:
- "6379:6379"
networks:
- qa-network
volumes:
- qa-redis-data:/data
command: redis-server --appendonly yes
volumes:
qa-db-data:
qa-redis-data:
networks:
qa-network:
driver: bridge
Шаг 3: Управление Тестовыми Данными
# test_data_manager.py
import psycopg2
from faker import Faker
import random
class TestDataManager:
"""Управлять тестовыми данными для окружения QA"""
def __init__(self, db_connection_string):
self.conn = psycopg2.connect(db_connection_string)
self.fake = Faker('ru_RU') # Русский
def reset_database(self):
"""Сбросить базу данных к чистому состоянию"""
with self.conn.cursor() as cursor:
# Очистить все таблицы (уважая внешние ключи)
cursor.execute("""
TRUNCATE TABLE
orders,
order_items,
products,
users,
addresses
CASCADE
""")
self.conn.commit()
print("Сброс базы данных завершён")
def seed_users(self, count=100):
"""Создать тестовых пользователей"""
with self.conn.cursor() as cursor:
users = []
for _ in range(count):
user = {
'email': self.fake.email(),
'first_name': self.fake.first_name(),
'last_name': self.fake.last_name(),
'password_hash': '$2b$10$EIXexample', # Предварительно хэшированный пароль
'created_at': self.fake.date_time_between(start_date='-1y')
}
users.append(user)
cursor.execute("""
INSERT INTO users (email, first_name, last_name, password_hash, created_at)
VALUES (%(email)s, %(first_name)s, %(last_name)s, %(password_hash)s, %(created_at)s)
""", user)
self.conn.commit()
print(f"Создано {count} тестовых пользователей")
def create_known_test_accounts(self):
"""Создать известные тестовые учётные записи для ручного тестирования"""
test_accounts = [
{
'email': 'тест.пользователь@example.com',
'password': 'Тест123!',
'first_name': 'Тестовый',
'last_name': 'Пользователь',
'role': 'user'
},
{
'email': 'admin@example.com',
'password': 'Admin123!',
'first_name': 'Админ',
'last_name': 'Пользователь',
'role': 'admin'
}
]
with self.conn.cursor() as cursor:
for account in test_accounts:
cursor.execute("""
INSERT INTO users (email, password_hash, first_name, last_name, role)
VALUES (%s, %s, %s, %s, %s)
ON CONFLICT (email) DO UPDATE
SET password_hash = EXCLUDED.password_hash
""", (
account['email'],
'$2b$10$EIXexample', # Предварительно хэшированный пароль
account['first_name'],
account['last_name'],
account['role']
))
self.conn.commit()
print("Созданы известные тестовые учётные записи")
def refresh_test_data(self):
"""Полное обновление тестовых данных"""
print("Начинается обновление тестовых данных...")
self.reset_database()
self.create_known_test_accounts()
self.seed_users(100)
print("Обновление тестовых данных завершено!")
Шаг 4: Конфигурация Окружения
# config.py - Специфичная для окружения конфигурация
import os
from enum import Enum
class Environment(Enum):
DEVELOPMENT = "development"
QA = "qa"
STAGING = "staging"
PRODUCTION = "production"
class Config:
"""Базовая конфигурация"""
SECRET_KEY = os.getenv('SECRET_KEY')
DATABASE_URL = os.getenv('DATABASE_URL')
REDIS_URL = os.getenv('REDIS_URL')
class QAConfig(Config):
"""Конфигурация окружения QA"""
DEBUG = False
LOG_LEVEL = "INFO"
# Использовать тестовые сервисы
EMAIL_BACKEND = "mailtrap"
PAYMENT_GATEWAY = "stripe_test"
# Специфичные для QA настройки
ALLOWED_HOSTS = ["qa.myapp.com"]
CORS_ORIGINS = ["https://qa.myapp.com"]
# Обновление тестовых данных
AUTO_REFRESH_TEST_DATA = True
TEST_DATA_REFRESH_TIME = "03:00" # 3 утра ежедневно
Контейнеризация с Docker
# Dockerfile для тестового окружения
FROM python:3.9-slim
WORKDIR /app
# Установить системные зависимости
RUN apt-get update && apt-get install -y \
postgresql-client \
redis-tools \
curl \
&& rm -rf /var/lib/apt/lists/*
# Установить зависимости Python
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Скопировать код приложения
COPY . .
# Создать пользователя без прав root
RUN useradd -m -u 1000 appuser && \
chown -R appuser:appuser /app
USER appuser
# Health check
HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
EXPOSE 3000
CMD ["python", "app.py"]
Лучшие Практики
1. Изоляция Окружения
# Чек-лист Изоляции Окружения
✓ Отдельная инфраструктура (VPC, сети)
✓ Отдельные базы данных (без общих экземпляров БД)
✓ Отдельные учётные данные (уникальные пароли, API ключи)
✓ Отдельный мониторинг (специфичные для окружения оповещения)
✓ Сегментация сети (файерволы, группы безопасности)
✓ Контроль доступа (разрешения на основе ролей)
2. Управление Конфигурацией
# Использовать переменные окружения для конфигурации
# .env.qa
# База Данных
DATABASE_HOST=qa-db.internal.company.com
DATABASE_PORT=5432
DATABASE_NAME=myapp_qa
DATABASE_USER=qa_user
DATABASE_PASSWORD=${SECRET_DB_PASSWORD}
# Redis
REDIS_HOST=qa-redis.internal.company.com
REDIS_PORT=6379
# API Ключи (тестовый режим)
STRIPE_API_KEY=sk_test_xxxxx
SENDGRID_API_KEY=SG.test.xxxxx
# Feature Flags
FEATURE_NEW_CHECKOUT=true
FEATURE_AI_RECOMMENDATIONS=false
3. Автоматизированная Настройка Окружения
#!/bin/bash
# setup-qa-environment.sh
set -e
echo "Настройка окружения QA..."
# 1. Провизионировать инфраструктуру
echo "Провизионирование инфраструктуры..."
cd terraform
terraform init
terraform apply -auto-approve
# 2. Развернуть приложение
echo "Развёртывание приложения..."
cd ../
docker-compose -f docker-compose.qa.yml up -d
# 3. Дождаться готовности сервисов
echo "Ожидание сервисов..."
./wait-for-services.sh
# 4. Запустить миграции базы данных
echo "Запуск миграций..."
docker-compose -f docker-compose.qa.yml exec app python manage.py migrate
# 5. Загрузить тестовые данные
echo "Загрузка тестовых данных..."
docker-compose -f docker-compose.qa.yml exec app python seed_data.py
echo "Настройка окружения QA завершена!"
echo "Доступ по адресу: https://qa.myapp.com"
4. Мониторинг Здоровья Окружения
# environment_health_check.py
import requests
import psycopg2
import redis
class EnvironmentHealthCheck:
"""Мониторить здоровье тестового окружения"""
def __init__(self, config):
self.config = config
self.results = []
def check_application(self):
"""Проверить, отвечает ли приложение"""
try:
response = requests.get(f"{self.config['app_url']}/health", timeout=5)
if response.status_code == 200:
self.results.append(("Приложение", "✓ Здоровое"))
else:
self.results.append(("Приложение", f"✗ Нездоровое (Статус: {response.status_code})"))
except Exception as e:
self.results.append(("Приложение", f"✗ Недоступно ({str(e)})"))
def check_database(self):
"""Проверить подключение к базе данных"""
try:
conn = psycopg2.connect(self.config['database_url'])
with conn.cursor() as cursor:
cursor.execute("SELECT 1")
result = cursor.fetchone()
if result:
self.results.append(("База Данных", "✓ Здоровая"))
conn.close()
except Exception as e:
self.results.append(("База Данных", f"✗ Недоступна ({str(e)})"))
def run_all_checks(self):
"""Запустить все проверки здоровья"""
print("Проверка Здоровья Окружения")
print("=" * 50)
self.check_application()
self.check_database()
for service, status in self.results:
print(f"{service:.<30} {status}")
print("=" * 50)
return all("✓" in status for _, status in self.results)
Заключение
Хорошо настроенное тестовое окружение фундаментально для эффективного тестирования. Следуя практикам инфраструктуры как кода, поддерживая паритет окружений, систематически управляя тестовыми данными и автоматизируя процессы настройки, вы обеспечиваете надёжное, повторяемое тестирование, которое ловит проблемы до того, как они достигнут продакшна.
Ключевые выводы:
- Использовать отдельные окружения для разных этапов тестирования
- Автоматизировать провизионирование и конфигурацию окружения
- Систематически управлять тестовыми данными
- Непрерывно мониторить здоровье окружения
- Контейнеризировать приложения для согласованности
- Документировать процедуры настройки окружения
Независимо от того, настраиваете ли вы простое локальное окружение или сложную многоуровневую тестовую инфраструктуру, эти принципы и практики помогут вам построить надёжные, поддерживаемые тестовые окружения, которые поддерживают ваши цели обеспечения качества.