← Назад к вопросам

Как сделать общую авторизацию для всех тестов?

2.0 Middle🔥 111 комментариев
#Теория тестирования

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Стратегия реализации общей авторизации в автоматизированных тестах

Реализация общей авторизации — критически важный компонент тестовой инфраструктуры, позволяющий избежать дублирования кода, уменьшить время выполнения тестов и повысить их стабильность. Вот комплексный подход к решению этой задачи.

Архитектурные подходы

Использование хуков в Pytest — наиболее популярный и эффективный метод в Python-стеках:

import pytest
import requests
from typing import Dict, Any

@pytest.fixture(scope="session")
def auth_token() -> str:
    """Фикстура для получения токена авторизации на уровне сессии"""
    credentials = {
        "username": "test_user",
        "password": "test_password"
    }
    
    response = requests.post(
        "https://api.example.com/auth/login",
        json=credentials
    )
    
    assert response.status_code == 200, "Авторизация не удалась"
    token_data = response.json()
    
    return token_data["access_token"]

@pytest.fixture(scope="function")
def authorized_client(auth_token: str) -> requests.Session:
    """Фикстура для создания авторизованной HTTP-сессии"""
    session = requests.Session()
    session.headers.update({
        "Authorization": f"Bearer {auth_token}",
        "Content-Type": "application/json"
    })
    
    # Добавляем автоматическую проверку срока действия токена
    yield session
    session.close()

Иерархия областей видимости фикстур позволяет оптимизировать процесс:

  • scope="session" — токен получается один раз за весь прогон тестов
  • scope="module" — переиспользование в рамках модуля
  • scope="class" — для тестовых классов
  • scope="function" — для каждого теста отдельно (наименее эффективно)

Расширенная реализация с обработкой исключений

import pytest
import requests
from requests.exceptions import RequestException
from datetime import datetime, timedelta

class AuthManager:
    """Менеджер для управления авторизацией"""
    
    def __init__(self):
        self._token = None
        self._token_expiry = None
        self._base_url = "https://api.example.com"
        
    def get_token(self, force_refresh: bool = False) -> str:
        """Получение токена с кэшированием и обновлением"""
        if (force_refresh or 
            self._token is None or 
            self._token_expiry is None or 
            datetime.now() >= self._token_expiry):
            
            self._refresh_token()
        
        return self._token
    
    def _refresh_token(self):
        """Обновление токена с обработкой ошибок"""
        try:
            response = requests.post(
                f"{self._base_url}/auth/login",
                json={
                    "username": self._get_credentials()["username"],
                    "password": self._get_credentials()["password"]
                },
                timeout=10
            )
            
            if response.status_code == 200:
                token_data = response.json()
                self._token = token_data["access_token"]
                # Устанавливаем время истечения (минус 30 секунд буфер)
                expires_in = token_data.get("expires_in", 3600)
                self._token_expiry = datetime.now() + timedelta(seconds=expires_in - 30)
            else:
                raise AuthException(f"Ошибка авторизации: {response.status_code}")
                
        except RequestException as e:
            raise AuthException(f"Сетевая ошибка при авторизации: {str(e)}")
    
    def _get_credentials(self) -> Dict[str, str]:
        """Безопасное получение учетных данных"""
        # На практике используйте переменные окружения или секреты
        return {
            "username": "test_user",
            "password": "test_password"
        }

@pytest.fixture(scope="session")
def auth_manager():
    """Фикстура для менеджера авторизации"""
    return AuthManager()

Интеграция с различными фреймворками

Для Selenium WebDriver (UI-тестирование):

from selenium import webdriver
from selenium.webdriver.common.by import By

@pytest.fixture
def authorized_driver(auth_token):
    """Фикстура для авторизованного браузера"""
    driver = webdriver.Chrome()
    
    # Устанавливаем токен в localStorage или cookies
    driver.get("https://example.com")
    
    # Внедряем токен через JavaScript
    driver.execute_script(f"""
        localStorage.setItem('auth_token', '{auth_token}');
        window.location.reload();
    """)
    
    yield driver
    driver.quit()

Для Playwright (современная альтернатива Selenium):

// Пример на JavaScript для Playwright
const { test, expect } = require('@playwright/test');

test.beforeAll(async ({ browser }) => {
  // Получаем токен через API
  const token = await getAuthToken();
  
  // Создаем контекст с заранее установленными куками
  const context = await browser.newContext({
    storageState: {
      cookies: [{
        name: 'session_token',
        value: token,
        domain: 'example.com',
        path: '/'
      }]
    }
  });
  
  global.authorizedPage = await context.newPage();
});

Ключевые практики и рекомендации

Безопасность и конфигурация:

  • Никогда не храните учетные данные в коде — используйте переменные окружения или системы управления секретами
  • Используйте различные наборы учетных данных для разных окружений (dev, staging, prod)
  • Реализуйте механизм ротации токенов и автоматического обновления

Оптимизация производительности:

  • Кэшируйте токены на уровне сессии для уменьшения количества запросов
  • Используйте параллельный запуск тестов с общей авторизацией
  • Реализуйте ленивую загрузку токенов (только при первом использовании)

Обработка ошибок и отказоустойчивость:

  • Добавляйте повторные попытки при неудачной авторизации
  • Реализуйте деградацию функциональности — возможность запуска тестов без авторизации (если допустимо)
  • Ведите логирование всех операций авторизации для отладки

Интеграция с CI/CD:

  • Настройте предварительную авторизацию на этапе подготовки тестового окружения
  • Используйте Service Accounts вместо пользовательских учетных записей
  • Реализуйте механизм очистки сессий после завершения тестов

Расширенные сценарии

Для микросервисных архитектур может потребоваться несколько уровней авторизации. В этом случае реализуйте фасад авторизации, который управляет множеством токенов:

class MultiServiceAuth:
    """Управление авторизацией для нескольких сервисов"""
    
    def __init__(self):
        self._tokens = {}
    
    def get_service_token(self, service_name: str) -> str:
        if service_name not in self._tokens:
            self._tokens[service_name] = self._authenticate_to_service(service_name)
        
        return self._tokens[service_name]

Мониторинг и аналитика

Инструментируйте процесс авторизации для сбора метрик:

  • Время получения/обновления токенов
  • Процент успешных авторизаций
  • Частота использования различных учетных записей

Заключение

Правильная реализация общей авторизации требует баланса между производительностью, безопасностью и поддерживаемостью. Начните с простой фикстуры на уровне сессии, затем постепенно добавляйте обработку ошибок, кэширование и механизмы обновления токенов. Используйте абстракции и dependency injection для обеспечения гибкости и тестируемости решения. Регулярно пересматривайте и обновляйте механизм авторизации в соответствии с изменениями в тестируемой системе и появлением новых инструментов в экосистеме автоматизации.

Как сделать общую авторизацию для всех тестов? | PrepBro