chore: 重构前基线 — 9 个 sync task 全部 ok + akshare 移除 + mairui 资金流接入
状态: - 9 个 sync task(stock_basic / kline_daily / kline_index / kline_5min / moneyflow / industry_sector / sector_features / share_snapshot / market_regime) - 数据源:baostock + mairui + 雪球(pysnowball) + 新浪(4 个) - 项目级约束:永远不用 akshare(已落实) - kline_5min 改用 DB 快照统一全量/增量逻辑 - 零后端 Chrome 扩展 xueqiu_sync(独立项目)
This commit is contained in:
@@ -0,0 +1 @@
|
||||
"""tests 包标记。"""
|
||||
@@ -0,0 +1,10 @@
|
||||
"""pytest 配置:让测试可以直接 `import app`。
|
||||
|
||||
只要把 tests/ 和 app/ 都放进 sys.path 即可。
|
||||
"""
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
if str(ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(ROOT))
|
||||
@@ -0,0 +1,93 @@
|
||||
"""冒烟测试:不依赖 MySQL/网络,只验证 import + 基本逻辑。
|
||||
|
||||
跑:pytest tests/test_smoke.py -v
|
||||
"""
|
||||
import pytest
|
||||
|
||||
|
||||
def test_import_config():
|
||||
from app.core.config import settings
|
||||
assert settings is not None
|
||||
assert hasattr(settings, "mysql_host")
|
||||
|
||||
|
||||
def test_import_data_source_base():
|
||||
from app.core.datasource.base import DataSource, FetchResult, registry
|
||||
assert DataSource is not None
|
||||
assert FetchResult is not None
|
||||
assert registry is not None
|
||||
# registry 应该是 dict-like
|
||||
assert hasattr(registry, "register")
|
||||
assert hasattr(registry, "get")
|
||||
|
||||
|
||||
def test_import_sync_base():
|
||||
from app.core.sync.base import SyncTask, _is_market_closed, _effective_sync_end
|
||||
assert SyncTask is not None
|
||||
assert isinstance(_is_market_closed(), bool)
|
||||
assert isinstance(_effective_sync_end(), str)
|
||||
# 同步任务基类不允许空 dataset_id
|
||||
with pytest.raises(ValueError):
|
||||
SyncTask()
|
||||
|
||||
|
||||
def test_tasks_registry():
|
||||
from app.tasks import TASKS, get_task
|
||||
assert isinstance(TASKS, dict)
|
||||
# 注:每次新增 task 都要更新这里的数字
|
||||
# 当前 9 个:stock_basic, kline_daily, kline_index, kline_5min, moneyflow,
|
||||
# industry_sector, sector_features, share_snapshot, market_regime
|
||||
assert len(TASKS) == 9
|
||||
# get_task 应该返回实例
|
||||
task = get_task("kline_daily")
|
||||
assert task.dataset_id == "kline_daily"
|
||||
|
||||
|
||||
def test_sync_definitions():
|
||||
from app.core.sync.registry import SYNC_DEFINITIONS
|
||||
assert len(SYNC_DEFINITIONS) == 9
|
||||
# 所有 dataset_id 应唯一
|
||||
ids = [d["dataset_id"] for d in SYNC_DEFINITIONS]
|
||||
assert len(set(ids)) == 9
|
||||
|
||||
|
||||
def test_build_default_registry():
|
||||
"""不连接网络,只看是否能完成注册(部分源 may not available 不影响注册)。"""
|
||||
from app.core.datasource.base import registry
|
||||
from app.core.datasource.registry import build_default_registry
|
||||
build_default_registry()
|
||||
keys = [s.key for s in registry.all()]
|
||||
assert "datasource_xinlang" in keys
|
||||
assert "datasource_baostock" in keys
|
||||
assert "datasource_mairui" in keys
|
||||
# akshare 已移除(项目级决策:永远不用)
|
||||
assert "datasource_akshare" not in keys
|
||||
assert "datasource_xueqiu" in keys
|
||||
|
||||
|
||||
def test_data_source_abstract():
|
||||
"""DataSource 抽象方法未实现时不应能被直接实例化。"""
|
||||
from app.core.datasource.base import DataSource
|
||||
with pytest.raises(TypeError):
|
||||
DataSource() # 抽象方法未实现
|
||||
|
||||
|
||||
def test_api_health_route():
|
||||
"""FastAPI 加载 + /api/health 路由可访问。"""
|
||||
from fastapi.testclient import TestClient
|
||||
from app.api.main import app
|
||||
|
||||
client = TestClient(app)
|
||||
resp = client.get("/api/health")
|
||||
assert resp.status_code == 200
|
||||
body = resp.json()
|
||||
assert body.get("status") == "ok"
|
||||
|
||||
|
||||
def test_effective_sync_end_format():
|
||||
from app.core.sync.base import _effective_sync_end
|
||||
s = _effective_sync_end()
|
||||
# YYYY-MM-DD 共 10 字符
|
||||
assert len(s) == 10
|
||||
assert s[4] == "-"
|
||||
assert s[7] == "-"
|
||||
Reference in New Issue
Block a user