ruwiki-test/tests/conftest.py

179 lines
5.0 KiB
Python
Raw Normal View History

2025-07-11 21:28:58 +02:00
import asyncio
import tempfile
from collections.abc import Generator
from pathlib import Path
from unittest.mock import AsyncMock, MagicMock
import pytest
from openai.types.chat import ChatCompletion, ChatCompletionMessage
from openai.types.chat.chat_completion import Choice
from src.models import AppConfig, Article, ArticleCreate, ProcessingStatus
@pytest.fixture(scope="session")
def event_loop() -> Generator[asyncio.AbstractEventLoop, None, None]:
"""Создать event loop для всей сессии тестов."""
loop = asyncio.new_event_loop()
yield loop
loop.close()
@pytest.fixture
def test_config() -> AppConfig:
"""Тестовая конфигурация."""
with tempfile.TemporaryDirectory() as temp_dir:
db_path = Path(temp_dir) / "test.db"
return AppConfig(
openai_api_key="test_key",
openai_model="gpt-4o-mini",
db_path=str(db_path),
max_concurrent_llm=2,
openai_rpm=10,
max_concurrent_wiki=5,
prompt_template_path="src/prompt.txt",
log_level="DEBUG",
)
@pytest.fixture
def sample_wiki_urls() -> list[str]:
"""Список тестовых URL википедии."""
return [
"https://ru.wikipedia.org/wiki/Тест",
"https://ru.wikipedia.org/wiki/Пример",
"https://ru.wikipedia.org/wiki/Образец",
]
@pytest.fixture
def invalid_urls() -> list[str]:
"""Список невалидных URL."""
return [
"https://example.com/invalid",
"https://en.wikipedia.org/wiki/English",
"not_a_url",
"",
"https://ru.wikipedia.org/wiki/",
]
@pytest.fixture
def sample_wikitext() -> str:
return """'''Тест''' — это проверка чего-либо.
== Определение ==
Тест может проводиться для различных целей:
* Проверка знаний
* Проверка работоспособности
* Проверка качества
== История ==
Тесты использовались с древних времён.
{{навигация|тема=Тестирование}}
[[Категория:Тестирование]]"""
@pytest.fixture
def simplified_text() -> str:
return """'''Тест''' — это проверка чего-либо для школьников.
== Что такое тест ==
Тест помогает проверить:
* Знания учеников
* Как работают устройства
* Качество продуктов
== Когда появились тесты ==
Люди проверяли друг друга очень давно.
###END###"""
@pytest.fixture
def sample_article_data() -> ArticleCreate:
return ArticleCreate(
url="https://ru.wikipedia.org/wiki/Тест",
title="Тест",
raw_text="Тестовый wiki-текст",
)
@pytest.fixture
def sample_article(sample_article_data: ArticleCreate) -> Article:
return Article(
id=1,
url=sample_article_data.url,
title=sample_article_data.title,
raw_text=sample_article_data.raw_text,
status=ProcessingStatus.PENDING,
)
@pytest.fixture
def completed_article(sample_article: Article, simplified_text: str) -> Article:
article = sample_article.model_copy()
article.mark_completed(
simplified_text=simplified_text,
token_count_raw=100,
token_count_simplified=50,
processing_time=2.5,
)
return article
@pytest.fixture
def mock_openai_response() -> ChatCompletion:
return ChatCompletion(
id="test_completion",
object="chat.completion",
created=1234567890,
model="gpt-4o-mini",
choices=[
Choice(
index=0,
message=ChatCompletionMessage(
role="assistant",
content="Упрощённый текст для школьников.\n\n###END###",
),
finish_reason="stop",
)
],
usage=None,
)
@pytest.fixture
def temp_input_file(sample_wiki_urls: list[str]) -> Generator[str, None, None]:
with tempfile.NamedTemporaryFile(mode="w", suffix=".txt", delete=False) as f:
for url in sample_wiki_urls:
f.write(f"{url}\n")
f.write("# Комментарий\n")
f.write("\n")
f.write("https://ru.wikipedia.org/wiki/Дубликат\n")
f.write("https://ru.wikipedia.org/wiki/Дубликат\n")
temp_path = f.name
yield temp_path
Path(temp_path).unlink(missing_ok=True)
@pytest.fixture
async def mock_wiki_client() -> AsyncMock:
mock_client = AsyncMock()
mock_page = MagicMock()
mock_page.exists = True
mock_page.redirect = False
mock_page.text.return_value = "Тестовый wiki-текст"
mock_client.pages = {"Тест": mock_page}
return mock_client
@pytest.fixture
async def mock_openai_client() -> AsyncMock:
mock_client = AsyncMock()
return mock_client