This repository has been archived on 2026-08-07. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
starmen1265 1c1c88e2cf test(15-00): add test infrastructure placeholders for Phase 15
创建了测试基础设施,为后续计划提供测试框架。

## 创建的文件

1. **tests/test_processors/test_srt.py** - SRTProcessor 配置集成测试占位符
   - TestConfigIntegration 测试类
   - 5 个测试占位符(pytest.skip)

2. **tests/test_backward_compat.py** - 向后兼容性测试
   - TestBackwardCompatibility 测试类
   - 部分测试已实现(来自计划 15-01)
   - 部分测试占位符(pytest.skip)

3. **tests/conftest.py** - 添加共享 fixtures
   - temp_env_vars fixture:临时环境变量管理
   - mock_kbsettings fixture:Mock KBSettings 实例
   - 添加 os 模块导入

## 偏离说明

计划要求所有测试都是占位符(pytest.skip),但实际上:
- test_config.py 已由计划 15-01 实现完整测试
- test_backward_compat.py 有部分实现

原因:计划 15-01 在 15-00 之前执行,导致测试不是占位符。

## 验证

- pytest 发现所有新增测试类和测试函数
- 测试文件结构符合项目规范

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 23:02:12 +08:00

237 lines
6.7 KiB
Python

"""共享测试 fixtures 和配置"""
import os
from typing import Optional
from unittest.mock import Mock
from pathlib import Path
from requests.exceptions import ConnectionError, Timeout, HTTPError
import pytest
from kb_workflow.srt.parser import Segment
class MockAIClient:
"""模拟 AI 客户端"""
def __init__(self, response: str = "Mock AI response"):
self.response = response
def generate(
self,
prompt: str,
max_tokens: int = 16000,
disable_reasoning: Optional[bool] = None
) -> str:
"""生成模拟响应"""
return self.response
@pytest.fixture
def mock_ai_client():
"""提供模拟 AI 客户端"""
return MockAIClient()
@pytest.fixture
def sample_segments():
"""提供示例字幕分段数据"""
return [
{"index": 1, "start": "00:00:00,000", "end": "00:00:05,000", "text": "大家好,欢迎来到我的频道"},
{"index": 2, "start": "00:00:05,000", "end": "00:00:10,000", "text": "今天我们要讲的是机器学习的基础知识"},
{"index": 3, "start": "00:00:10,000", "end": "00:00:15,000", "text": "首先,什么是机器学习"},
{"index": 4, "start": "00:00:15,000", "end": "00:00:20,000", "text": "机器学习是人工智能的一个分支"},
{"index": 5, "start": "00:00:20,000", "end": "00:00:25,000", "text": "它让计算机能够从数据中学习"},
]
@pytest.fixture
def sample_metadata():
"""提供示例视频元数据"""
return {
"title": "机器学习入门教程",
"category": "教育",
"tags": ["编程", "AI", "教程"],
"description": "从零开始学习机器学习"
}
@pytest.fixture
def sample_metadata_movie():
"""提供电影类型示例元数据"""
return {
"title": "星际穿越",
"category": "影视",
"tags": ["科幻", "电影"],
"description": "一部关于太空探索的科幻电影"
}
# ============================================================================
# Phase 14 Fixtures: 鲁棒性和成本控制测试
# ============================================================================
@pytest.fixture
def long_text_sample():
"""长文本样本(>5000 字符,用于分块测试)"""
# 生成一个超过 5000 字符的文本,包含多个句子
sentences = ["这是一个测试句子。" * 10] * 15 # 约 6000 字符
return " ".join(sentences)
@pytest.fixture
def mock_ai_client_network_error():
"""模拟网络错误的 AI 客户端"""
client = Mock()
client.api_key = "test_key"
client.generate = Mock(side_effect=ConnectionError("Network error"))
return client
@pytest.fixture
def mock_ai_client_timeout():
"""模拟超时的 AI 客户端"""
client = Mock()
client.api_key = "test_key"
client.generate = Mock(side_effect=Timeout("Request timeout"))
return client
@pytest.fixture
def mock_ai_client_rate_limit():
"""模拟限流的 AI 客户端"""
response = Mock()
response.status_code = 429
client = Mock()
client.api_key = "test_key"
def generate_side_effect(*args, **kwargs):
raise HTTPError(response=response)
client.generate = Mock(side_effect=generate_side_effect)
return client
@pytest.fixture
def mock_ai_client_api_error():
"""模拟 API 错误的 AI 客户端(不可恢复)"""
response = Mock()
response.status_code = 400
client = Mock()
client.api_key = "test_key"
def generate_side_effect(*args, **kwargs):
raise HTTPError(response=response)
client.generate = Mock(side_effect=generate_side_effect)
return client
@pytest.fixture
def mock_ai_client_parse_error():
"""模拟解析失败的 AI 客户端"""
client = Mock()
client.api_key = "test_key"
# 第一次返回无效 JSON
client.generate = Mock(return_value="Invalid JSON response")
return client
@pytest.fixture
def mock_ai_client_success():
"""模拟成功的 AI 客户端"""
import json
client = Mock()
client.api_key = "test_key"
client.generate = Mock(return_value=json.dumps({
"video_type": "知识类",
"segments": [
{
"title": "测试标题",
"content": "测试内容",
"start_index": 0,
"end_index": 10
}
],
"actual_segment_count": 1
}, ensure_ascii=False))
return client
@pytest.fixture
def temp_cache_dir(tmp_path):
"""临时缓存目录"""
cache_dir = tmp_path / "cache" / "semantic"
return cache_dir
@pytest.fixture
def semantic_cache(temp_cache_dir):
"""语义分段缓存实例"""
from kb_workflow.srt.cache.semantic_cache import SemanticCache
return SemanticCache(cache_dir=temp_cache_dir)
@pytest.fixture
def long_subtitle_segments():
"""长字幕分段样本(>5000 字符)"""
segments = []
for i in range(100):
segments.append(Segment(
id=i + 1,
start_time=i * 1.0,
end_time=(i + 1) * 1.0,
text=f"这是第 {i + 1} 句字幕内容。" * 5
))
return segments
# ============================================================================
# Phase 15 Fixtures: 配置集成测试
# ============================================================================
@pytest.fixture
def temp_env_vars(monkeypatch):
"""临时环境变量 fixture,测试后自动清理"""
original_env = {}
saved_vars = {}
def _set_env(env_dict):
nonlocal original_env, saved_vars
# 保存原始值
for key in env_dict.keys():
original_env[key] = os.environ.get(key)
# 设置新值
for key, value in env_dict.items():
if value is None:
os.environ.pop(key, None)
else:
os.environ[key] = value
saved_vars[key] = value
yield _set_env
# 清理:恢复原始环境变量
for key, original_value in original_env.items():
if original_value is None:
os.environ.pop(key, None)
else:
os.environ[key] = original_value
@pytest.fixture
def mock_kbsettings():
"""Mock KBSettings fixture,用于隔离测试环境"""
from kb_workflow.pipeline.config import KBSettings
from kb_workflow.pipeline.config import get_settings
mock_settings = MagicMock(spec=KBSettings)
mock_settings.enable_semantic_segmentation = True
mock_settings.base_path = "/tmp/kb"
mock_settings.archive_path = "/tmp/archive"
mock_settings.hf_token = MagicMock()
mock_settings.hf_token.get_secret_value.return_value = ""
mock_settings.zhihu_cookie = MagicMock()
mock_settings.zhihu_cookie.get_secret_value.return_value = ""
return mock_settings