重构: 迁移后端代码到 app 目录,前端移动到 WebUI,添加完整测试套件

主要变更:
- 后端代码从根目录迁移到 app/ 目录
- 前端代码从 frontend/ 重命名为 WebUI/
- 更新所有导入路径以适配新结构
- 提取公共 API 响应函数到 app/api/common.py
- 精简验证器服务代码
- 更新启动脚本和文档

测试:
- 新增完整测试套件 (tests/)
- 单元测试: 模型、仓库层
- 集成测试: 覆盖所有 22+ API 端点
- E2E 测试: 4个完整工作流场景
- 添加 pytest 配置和测试运行脚本
This commit is contained in:
祀梦
2026-04-04 13:32:36 +08:00
parent df3cc87f88
commit 38bd66128b
109 changed files with 2017 additions and 548 deletions

136
tests/unit/test_models.py Normal file
View File

@@ -0,0 +1,136 @@
"""模型单元测试"""
import pytest
from datetime import datetime
from app.models.domain import ProxyRaw, Proxy, PluginInfo
from app.models.schemas import (
ProxyCreate,
ProxyListRequest,
SettingsSchema,
BatchDeleteRequest,
)
class TestProxyRaw:
"""测试 ProxyRaw 领域模型"""
def test_create_proxy_raw(self):
"""测试创建原始代理"""
proxy = ProxyRaw("192.168.1.1", 8080, "http")
assert proxy.ip == "192.168.1.1"
assert proxy.port == 8080
assert proxy.protocol == "http"
def test_protocol_normalization(self):
"""测试协议标准化"""
proxy = ProxyRaw("192.168.1.1", 8080, "HTTP")
assert proxy.protocol == "http"
def test_invalid_protocol_defaults_to_http(self):
"""测试无效协议默认为 http"""
proxy = ProxyRaw("192.168.1.1", 8080, "invalid")
assert proxy.protocol == "http"
class TestProxy:
"""测试 Proxy 领域模型"""
def test_create_proxy(self):
"""测试创建代理实体"""
proxy = Proxy(
ip="192.168.1.1",
port=8080,
protocol="http",
score=50,
response_time_ms=100.5,
last_check=datetime.now(),
created_at=datetime.now(),
)
assert proxy.ip == "192.168.1.1"
assert proxy.score == 50
class TestPluginInfo:
"""测试 PluginInfo 领域模型"""
def test_create_plugin_info(self):
"""测试创建插件信息"""
plugin = PluginInfo(
id="test_plugin",
name="test_plugin",
display_name="测试插件",
description="用于测试",
enabled=True,
success_count=10,
failure_count=2,
)
assert plugin.id == "test_plugin"
assert plugin.enabled is True
assert plugin.success_count == 10
class TestProxyCreateSchema:
"""测试 ProxyCreate Pydantic 模型"""
def test_valid_proxy_create(self):
"""测试有效的代理创建"""
proxy = ProxyCreate(ip="192.168.1.1", port=8080, protocol="http")
assert proxy.ip == "192.168.1.1"
assert proxy.port == 8080
def test_port_validation(self):
"""测试端口验证"""
with pytest.raises(Exception):
ProxyCreate(ip="192.168.1.1", port=70000) # 超出范围
def test_protocol_validation(self):
"""测试协议验证"""
with pytest.raises(Exception):
ProxyCreate(ip="192.168.1.1", port=8080, protocol="invalid")
class TestProxyListRequest:
"""测试 ProxyListRequest 模式"""
def test_default_values(self):
"""测试默认值"""
request = ProxyListRequest()
assert request.page == 1
assert request.page_size == 20
assert request.sort_by == "last_check"
assert request.sort_order == "DESC"
def test_custom_values(self):
"""测试自定义值"""
request = ProxyListRequest(page=2, page_size=50, protocol="https")
assert request.page == 2
assert request.page_size == 50
assert request.protocol == "https"
class TestSettingsSchema:
"""测试 SettingsSchema"""
def test_default_settings(self):
"""测试默认设置"""
settings = SettingsSchema()
assert settings.crawl_timeout == 30
assert settings.validation_timeout == 10
assert settings.auto_validate is True
def test_custom_settings(self):
"""测试自定义设置"""
settings = SettingsSchema(crawl_timeout=60, auto_validate=False)
assert settings.crawl_timeout == 60
assert settings.auto_validate is False
class TestBatchDeleteRequest:
"""测试 BatchDeleteRequest"""
def test_valid_batch_delete(self):
"""测试有效的批量删除"""
request = BatchDeleteRequest(proxies=[
{"ip": "192.168.1.1", "port": 8080},
{"ip": "192.168.1.2", "port": 8081},
])
assert len(request.proxies) == 2