Подготовка новых моделей тестов

This commit is contained in:
2026-07-17 13:23:17 +03:00
parent b68f17f069
commit 0c1c2bd61c
65 changed files with 337 additions and 5147 deletions

View File

@@ -8,4 +8,5 @@
Пакет базовых классов для реализации тестов
"""
from .core_test_case import CoreTestCase
from .core_simple_test_case import CoreSimpleTestCase
from .core_user_story_test_case import CoreUserStoryTestCase

View File

@@ -0,0 +1,27 @@
# DRF Rack
# Библиотека классов расширений для Django REST Framework
#
# Автор: Николай В. Анохин <n.anokhin@xeaf.net>
# Все права защищены. Лицензия: MIT
"""
Описание класса CoreUserStoryTestCase
"""
from django.test import SimpleTestCase
from rest_framework.test import APIRequestFactory
from .request_test_case_mixin import RequestTestCaseMixin
class CoreSimpleTestCase(SimpleTestCase, RequestTestCaseMixin):
"""
Реализует методы для тестирования без использования БД
"""
def setUp(self):
"""
Настройка перед тестированием
"""
self.factory = APIRequestFactory()

View File

@@ -0,0 +1,78 @@
# DRF Rack
# Библиотека классов расширений для Django REST Framework
#
# Автор: Николай В. Анохин <n.anokhin@xeaf.net>
# Все права защищены. Лицензия: MIT
"""
Описание класса CoreUserStoryTestCase
"""
from typing import Any
from django.core.management import call_command
from django.test import TestCase
from rest_framework.request import Request
from rest_framework.test import APIRequestFactory
from net.xeaf.rack.enums import HttpMethod
from net.xeaf.rack.management.userstory import SessionTestData
from .request_test_case_mixin import RequestTestCaseMixin
class CoreUserStoryTestCase(TestCase, RequestTestCaseMixin):
"""
Реализует методы для тестирования пользовательских историй
"""
def setUp(self):
"""
Настройка перед тестированием
"""
call_command("rack_test_database")
self.factory = APIRequestFactory()
def create_i_ivanov_request(self, method: HttpMethod, path: str, headers: dict[str, str] | None = None, data: dict[str, Any] | None = None, query_params: dict[str, Any] | None = None) -> Request:
"""
Создает запрос от имени Ивана И. Иванова
:param method: HTTP метод (GET, POST, PUT, PATCH, DELETE)
:param path: URL путь
:param headers: Заголовки запроса
:param data: Данные для тела запроса
:param query_params: Параметры запроса
:return: Объект запроса с аутентификацией Ивана Иванова
"""
return self.create_authenticated_request(
method=method,
path=path,
headers=headers,
data=data,
query_params=query_params,
token=SessionTestData.IVANOV_SESSION_TOKEN,
)
def create_p_petrov_request(self, method: HttpMethod, path: str, headers: dict[str, str] | None = None, data: dict[str, Any] | None = None, query_params: dict[str, Any] | None = None) -> Request:
"""
Создает запрос от имени Петра П. Петрова
:param method: HTTP метод (GET, POST, PUT, PATCH, DELETE)
:param path: URL путь
:param headers: Заголовки запроса
:param data: Данные для тела запроса
:param query_params: Параметры запроса
:return: Объект запроса с аутентификацией Петра Петрова
"""
return self.create_authenticated_request(
method=method,
path=path,
headers=headers,
data=data,
query_params=query_params,
token=SessionTestData.PETROV_SESSION_TOKEN
)

View File

@@ -0,0 +1,164 @@
# DRF Rack
# Библиотека классов расширений для Django REST Framework
#
# Автор: Николай В. Анохин <n.anokhin@xeaf.net>
# Все права защищены. Лицензия: MIT
"""
Описание класса RequestTestCaseMixin
"""
import json
from typing import Any
from rest_framework.parsers import JSONParser
from rest_framework.request import Request
from rest_framework.test import APIRequestFactory
from net.xeaf.rack.enums import HttpMethod
from net.xeaf.rack.managers import SessionManager
from net.xeaf.rack.models import SessionModel
class RequestTestCaseMixin:
"""
Реализует методы для тестирования запросов
"""
factory: APIRequestFactory
""" Фабрика запросов """
def create_request(self,
method: HttpMethod,
path: str,
headers: dict[str, str] | None = None,
data: dict[str, Any] | None = None,
query_params: dict[str, str] | None = None,
auth: SessionModel | None = None) -> Request:
"""
Создает объект запроса для тестирования
:param method: HTTP метод (GET, POST, PUT, PATCH, DELETE)
:param path: URL путь
:param headers: Заголовки запроса
:param data: Данные для тела запроса
:param query_params: Параметры запроса
:param auth: Объект аутентификации (сессия)
:return: DRF Request объект
"""
# Уточняем значения параметров
headers = self.__prepare_headers(headers or {})
query_params = query_params or {}
data = data or {}
# Создаем внутренний объект запроса
match method:
case HttpMethod.GET:
wsgi_request = self.factory.get(path, data=query_params, **headers)
case HttpMethod.POST:
wsgi_request = self.factory.post(path, data=data, format='json', **headers)
case HttpMethod.PUT:
wsgi_request = self.factory.put(path, data=data, format='json', **headers)
case HttpMethod.PATCH:
wsgi_request = self.factory.patch(path, data=data, format='json', **headers)
case HttpMethod.DELETE:
wsgi_request = self.factory.delete(path, **headers)
case _:
wsgi_request = self.factory.generic(
method,
path,
content_type='application/json',
data=json.dumps(data) if data else ''
)
# Преобразуем к объекту запроса DRF
drf_request = Request(wsgi_request, parsers=[JSONParser()])
if method != HttpMethod.GET:
self.__assign_query_params(drf_request, query_params)
self.__assign_auth(drf_request, auth)
return drf_request
def create_authenticated_request(self,
method: HttpMethod,
path: str,
headers: dict[str, str] | None = None,
data: dict[str, Any] | None = None,
query_params: dict[str, str] | None = None,
token: str | None = None) -> Request:
"""
Создает объект авторизованного запроса для тестирования
:param method: HTTP метод (GET, POST, PUT, PATCH, DELETE)
:param path: URL путь
:param headers: Заголовки запроса
:param data: Данные для тела запроса
:param query_params: Параметры запроса
:param token: Токен сессии авторизации
:return: DRF Request объект
"""
# Получаем сессию
if token is None:
session = None
else:
session = SessionManager.find_by_token(token)
# Возвращаем объект запроса
return self.create_request(method=method, path=path, headers=headers, data=data, query_params=query_params, auth=session)
@classmethod
def __prepare_headers(cls, headers: dict[str, str]) -> dict[str, str]:
"""
Подготавливаем объект заголовков для передачи в фабрику
:param headers: Заголовки запроса
:return: Объект заголовков для фабрики
"""
wsgi_headers = {}
for key, value in headers.items():
if key.startswith('HTTP_'):
wsgi_headers[key] = value
else:
norm_key = key.upper().replace('-', '_')
if norm_key in ('CONTENT_TYPE', 'CONTENT_LENGTH'):
wsgi_headers[norm_key.lower()] = value
else:
wsgi_headers[f'HTTP_{norm_key}'] = value
return wsgi_headers
@classmethod
def __assign_query_params(cls, request: Request, query_params: dict[str, Any]) -> None:
"""
Присваивает параметры запроса в DRF Request объект
:param request: DRF Request объект
:param query_params: Параметры запроса
"""
# noinspection PyTypeChecker
request.query_params._mutable = True
for key, value in query_params.items():
request.query_params[key] = value
request.query_params._mutable = False
@classmethod
def __assign_auth(cls, request: Request, auth: SessionModel | None) -> None:
"""
Присваивает аутентификацию в DRF Request объект
:param request: Объект запроса
:param auth: Объект сессии пользователя
"""
if auth:
request.auth = auth
if hasattr(auth, 'account'):
request.user = auth.account