""" 翻译器测试 """ import pytest import asyncio from unittest.mock import Mock, AsyncMock, patch from src.translator import EPUBTranslator from src.llm_client import OpenRouterClient class TestEPUBTranslator: """EPUB 翻译器测试类""" @pytest.fixture def mock_config(self): """模拟配置""" return { 'openrouter': { 'api_key': 'test_key', 'base_url': 'https://openrouter.ai/api/v1', 'models': { 'test': 'google/gemini-2.0-flash-exp', 'production': 'google/gemini-exp-1206' }, 'rate_limits': { 'requests_per_minute': 60, 'concurrent_requests': 5 } }, 'translation': { 'chunk_size': 3, 'max_context_length': 8000, 'sample_ratio': 0.1, 'target_language': 'zh-CN', 'temperature': 0.3, 'max_tokens': 4000 }, 'processing': { 'skip_sections': ['acknowledgments'], 'include_sections': ['preface', 'chapter'], 'clean_patterns': ['\\[\\d+\\]'], 'min_paragraph_length': 20 }, 'output': { 'format': 'bilingual', 'filename_suffix': '_bilingual', 'preserve_images': True, 'preserve_css': True, 'output_dir': 'output' }, 'logging': { 'level': 'INFO', 'file': 'logs/test.log' } } @pytest.fixture def mock_translator(self, mock_config): """创建模拟翻译器""" with patch('src.translator.OpenRouterClient') as mock_client: mock_client.return_value.close = AsyncMock() translator = EPUBTranslator(mock_config) return translator def test_translator_initialization(self, mock_translator): """测试翻译器初始化""" assert mock_translator.config is not None assert mock_translator.text_processor is not None assert mock_translator.console is not None @pytest.mark.asyncio async def test_get_translation_estimate(self, mock_translator): """测试翻译估算""" # 模拟 EPUBParser with patch('src.translator.EPUBParser') as mock_parser: mock_parser.return_value.extract_translatable_content.return_value = [ { 'title': 'Test Chapter', 'content': '
Test paragraph content
' * 10, 'type': 'chapter' } ] # 模拟 text_processor mock_translator.text_processor.extract_paragraphs = Mock(return_value=[ {'text': 'Test paragraph content'} for _ in range(10) ]) estimate = await mock_translator.get_translation_estimate('test.epub') assert 'total_paragraphs' in estimate assert 'estimated_tokens' in estimate assert 'estimated_time_minutes' in estimate def test_get_translator_info(self, mock_translator): """测试获取翻译器信息""" # 模拟 llm_client mock_translator.llm_client.get_model_info = Mock(return_value={ 'test_model': 'test_model', 'production_model': 'prod_model' }) info = mock_translator.get_translator_info() assert 'version' in info assert 'llm_models' in info assert 'config' in info assert info['config']['chunk_size'] == 3 class TestOpenRouterClient: """OpenRouter 客户端测试类""" @pytest.fixture def mock_config(self): """模拟配置""" return { 'openrouter': { 'api_key': 'test_key', 'base_url': 'https://openrouter.ai/api/v1', 'models': { 'test': 'google/gemini-2.0-flash-exp', 'production': 'google/gemini-exp-1206' }, 'rate_limits': { 'requests_per_minute': 60, 'concurrent_requests': 5 } }, 'translation': { 'temperature': 0.3, 'max_tokens': 4000 } } def test_client_initialization_invalid_key(self, mock_config): """测试无效 API Key""" mock_config['openrouter']['api_key'] = 'YOUR_OPENROUTER_API_KEY' with pytest.raises(ValueError, match="请在配置文件中设置有效的 OpenRouter API Key"): OpenRouterClient(mock_config) @patch('src.llm_client.AsyncOpenAI') def test_client_initialization_valid(self, mock_openai, mock_config): """测试有效初始化""" client = OpenRouterClient(mock_config) assert client.models['test'] == 'google/gemini-2.0-flash-exp' assert client.models['production'] == 'google/gemini-exp-1206' mock_openai.assert_called_once() @patch('src.llm_client.AsyncOpenAI') def test_build_translation_prompt(self, mock_openai, mock_config): """测试翻译提示词构建""" client = OpenRouterClient(mock_config) prompt = client.build_translation_prompt( "Hello world", "This is a test book", {"technical_terms": {"API": "应用程序接口"}} ) assert "Hello world" in prompt assert "This is a test book" in prompt assert "API -> 应用程序接口" in prompt @patch('src.llm_client.AsyncOpenAI') def test_split_translation_result(self, mock_openai, mock_config): """测试翻译结果分割""" client = OpenRouterClient(mock_config) # 测试正常分割 translation = "第一段翻译\n\n第二段翻译\n\n第三段翻译" result = client._split_translation_result(translation, 3) assert len(result) == 3 assert result[0] == "第一段翻译" assert result[1] == "第二段翻译" assert result[2] == "第三段翻译" # 测试单段落 single_translation = "单段落翻译" result = client._split_translation_result(single_translation, 1) assert len(result) == 1 assert result[0] == "单段落翻译"