Files
myquant/finance/tests/test_dao_upsert.py
T
Simon 73d191b43a feat: 量化引擎加固 — 新增测试 + 数据/因子/回测层优化
- 新增 finance/tests/ 6 个测试套件(agents/backtest/dao_upsert/factors/features/fundamental_lookahead)
- 数据层: data_manager / dao 优化,新增 upsert 逻辑
- 因子层: 基本面因子抽象定位 _mapping、ROE/PE/PB 重构
- 回测层: vectorbt/engine 大改动(251 行),report 增强
- ML 层: features/backtest_integration 特征工程与回测优化
- CLI: agent_cli 重构
- config/settings 扩充配置项
2026-08-31 14:01:06 +08:00

69 lines
2.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
DAO 写库回归测试:验证 upsert(INSERT ... ON DUPLICATE KEY UPDATE)而非 pandas replace,
确保不 DROP 表、不丢失数据、DELETE+INSERT 不再分事务。
不使用真实 DB(用假 engine 捕获 SQL)。
"""
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import pandas as pd
import pytest
from unittest.mock import patch
from database import dao
from database.models import StockDaily
from sqlalchemy.dialects import mysql
class _RecConn:
"""记录最近一次执行的 SQL。"""
def __init__(self):
self.sql = None
def begin(self):
return self
def __enter__(self):
return self
def __exit__(self, *a):
pass
def execute(self, stmt):
self.sql = str(stmt.compile(dialect=mysql.dialect(), compile_kwargs={"literal_binds": True}))
return type("R", (), {"rowcount": 2})()
class _RecEngine:
def __init__(self):
self.conn = _RecConn()
def begin(self):
return self.conn
def _daily_df():
return pd.DataFrame({
'ts_code': ['000001.SZ', '600519.SH'],
'trade_date': ['20260601', '20260601'],
'open': [10.1, 99.0], 'high': [10.8, 101.0], 'low': [10.0, 98.0],
'close': [10.5, 100.0], 'pre_close': [10.2, 99.5],
'change': [0.3, 0.5], 'pct_chg': [2.94, 0.50], 'vol': [100, 200],
'amount': [1050, 19900], 'turnover_rate': [0.5, 0.2],
})
def test_save_daily_generates_upsert_not_replace():
eng = _RecEngine()
with patch('database.dao.get_engine', return_value=eng):
dao.save_daily(_daily_df())
sql = eng.conn.sql
assert "INSERT INTO" in sql and "mac_stock_daily" in sql
assert "ON DUPLICATE KEY UPDATE" in sql, "save_daily 必须用 upsert,避免旧版 DELETE+INSERT"
# 确保不会走 pandas replace(整表重建)
assert "DROP TABLE" not in sql.upper()
def test_save_daily_no_multi_transaction():
"""save_daily 只构造一次 upsert 语句,DELETE 与 INSERT 合并为原子语句。"""
eng = _RecEngine()
with patch('database.dao.get_engine', return_value=eng):
dao.save_daily(_daily_df())
# 生成的 SQL 不含独立 DELETE,确保无"删除已发生但插入失败"的非原子风险
assert "DELETE" not in eng.conn.sql.upper()