- 存储层重构: HDF5 → DuckDB(UPSERT模式、线程安全存储) - Sync类迁移: DataSync从sync.py迁移到api_daily.py(职责分离) - 模型模块重构: src/models → src/pipeline(更清晰的命名) - 新增因子模块: factors/momentum (MA、收益率排名)、factors/financial - 新增API接口: api_namechange、api_bak_basic - 新增训练入口: training模块(main.py、pipeline配置) - 工具函数统一: get_today_date等移至utils.py - 文档更新: AGENTS.md添加架构变更历史
165 lines
5.6 KiB
Python
165 lines
5.6 KiB
Python
"""Sync 接口测试规范与实现。
|
||
|
||
【测试规范】
|
||
1. 所有 sync 测试只使用 2018-01-01 到 2018-04-01 的数据
|
||
2. 只测试接口是否能正常返回数据,不测试落库逻辑
|
||
3. 对于按股票查询的接口,只测试 000001.SZ、000002.SZ 两支股票
|
||
4. 使用真实 API 调用,确保接口可用性
|
||
|
||
【测试范围】
|
||
- get_daily: 日线数据接口(按股票)
|
||
- sync_all_stocks: 股票基础信息接口
|
||
- sync_trade_cal_cache: 交易日历接口
|
||
- sync_namechange: 名称变更接口
|
||
- sync_bak_basic: 备用股票基础信息接口
|
||
"""
|
||
|
||
import pytest
|
||
import pandas as pd
|
||
from datetime import datetime
|
||
|
||
# 测试用常量
|
||
TEST_START_DATE = "20180101"
|
||
TEST_END_DATE = "20180401"
|
||
TEST_STOCK_CODES = ["000001.SZ", "000002.SZ"]
|
||
|
||
|
||
class TestGetDaily:
|
||
"""测试日线数据 get 接口(按股票查询)."""
|
||
|
||
def test_get_daily_single_stock(self):
|
||
"""测试 get_daily 获取单只股票数据."""
|
||
from src.data.api_wrappers.api_daily import get_daily
|
||
|
||
result = get_daily(
|
||
ts_code=TEST_STOCK_CODES[0],
|
||
start_date=TEST_START_DATE,
|
||
end_date=TEST_END_DATE,
|
||
)
|
||
|
||
# 验证返回了数据
|
||
assert isinstance(result, pd.DataFrame), "get_daily 应返回 DataFrame"
|
||
assert not result.empty, "get_daily 应返回非空数据"
|
||
|
||
def test_get_daily_has_required_columns(self):
|
||
"""测试 get_daily 返回的数据包含必要字段."""
|
||
from src.data.api_wrappers.api_daily import get_daily
|
||
|
||
result = get_daily(
|
||
ts_code=TEST_STOCK_CODES[0],
|
||
start_date=TEST_START_DATE,
|
||
end_date=TEST_END_DATE,
|
||
)
|
||
|
||
# 验证必要的列存在
|
||
required_columns = ["ts_code", "trade_date", "open", "high", "low", "close"]
|
||
for col in required_columns:
|
||
assert col in result.columns, f"get_daily 返回应包含 {col} 列"
|
||
|
||
def test_get_daily_multiple_stocks(self):
|
||
"""测试 get_daily 获取多只股票数据."""
|
||
from src.data.api_wrappers.api_daily import get_daily
|
||
|
||
results = {}
|
||
for code in TEST_STOCK_CODES:
|
||
result = get_daily(
|
||
ts_code=code,
|
||
start_date=TEST_START_DATE,
|
||
end_date=TEST_END_DATE,
|
||
)
|
||
results[code] = result
|
||
assert isinstance(result, pd.DataFrame), (
|
||
f"get_daily({code}) 应返回 DataFrame"
|
||
)
|
||
assert not result.empty, f"get_daily({code}) 应返回非空数据"
|
||
|
||
|
||
class TestSyncStockBasic:
|
||
"""测试股票基础信息 sync 接口."""
|
||
|
||
def test_sync_all_stocks_returns_data(self):
|
||
"""测试 sync_all_stocks 是否能正常返回数据."""
|
||
from src.data.api_wrappers.api_stock_basic import sync_all_stocks
|
||
|
||
result = sync_all_stocks()
|
||
|
||
# 验证返回了数据
|
||
assert isinstance(result, pd.DataFrame), "sync_all_stocks 应返回 DataFrame"
|
||
assert not result.empty, "sync_all_stocks 应返回非空数据"
|
||
|
||
def test_sync_all_stocks_has_required_columns(self):
|
||
"""测试 sync_all_stocks 返回的数据包含必要字段."""
|
||
from src.data.api_wrappers.api_stock_basic import sync_all_stocks
|
||
|
||
result = sync_all_stocks()
|
||
|
||
# 验证必要的列存在
|
||
required_columns = ["ts_code"]
|
||
for col in required_columns:
|
||
assert col in result.columns, f"sync_all_stocks 返回应包含 {col} 列"
|
||
|
||
|
||
class TestSyncTradeCal:
|
||
"""测试交易日历 sync 接口."""
|
||
|
||
def test_sync_trade_cal_cache_returns_data(self):
|
||
"""测试 sync_trade_cal_cache 是否能正常返回数据."""
|
||
from src.data.api_wrappers.api_trade_cal import sync_trade_cal_cache
|
||
|
||
result = sync_trade_cal_cache(
|
||
start_date=TEST_START_DATE,
|
||
end_date=TEST_END_DATE,
|
||
)
|
||
|
||
# 验证返回了数据
|
||
assert isinstance(result, pd.DataFrame), "sync_trade_cal_cache 应返回 DataFrame"
|
||
assert not result.empty, "sync_trade_cal_cache 应返回非空数据"
|
||
|
||
def test_sync_trade_cal_cache_has_required_columns(self):
|
||
"""测试 sync_trade_cal_cache 返回的数据包含必要字段."""
|
||
from src.data.api_wrappers.api_trade_cal import sync_trade_cal_cache
|
||
|
||
result = sync_trade_cal_cache(
|
||
start_date=TEST_START_DATE,
|
||
end_date=TEST_END_DATE,
|
||
)
|
||
|
||
# 验证必要的列存在
|
||
required_columns = ["cal_date", "is_open"]
|
||
for col in required_columns:
|
||
assert col in result.columns, f"sync_trade_cal_cache 返回应包含 {col} 列"
|
||
|
||
|
||
class TestSyncNamechange:
|
||
"""测试名称变更 sync 接口."""
|
||
|
||
def test_sync_namechange_returns_data(self):
|
||
"""测试 sync_namechange 是否能正常返回数据."""
|
||
from src.data.api_wrappers.api_namechange import sync_namechange
|
||
|
||
result = sync_namechange()
|
||
|
||
# 验证返回了数据(可能是空 DataFrame,因为是历史变更)
|
||
assert isinstance(result, pd.DataFrame), "sync_namechange 应返回 DataFrame"
|
||
|
||
|
||
class TestSyncBakBasic:
|
||
"""测试备用股票基础信息 sync 接口."""
|
||
|
||
def test_sync_bak_basic_returns_data(self):
|
||
"""测试 sync_bak_basic 是否能正常返回数据."""
|
||
from src.data.api_wrappers.api_bak_basic import sync_bak_basic
|
||
|
||
result = sync_bak_basic(
|
||
start_date=TEST_START_DATE,
|
||
end_date=TEST_END_DATE,
|
||
)
|
||
|
||
# 验证返回了数据
|
||
assert isinstance(result, pd.DataFrame), "sync_bak_basic 应返回 DataFrame"
|
||
# 注意:bak_basic 可能返回空数据,这是正常的
|
||
|
||
|
||
if __name__ == "__main__":
|
||
pytest.main([__file__, "-v"])
|