# -*- coding: utf-8 -*- """provider 方法面钉死测试(单一真相,issue #35 方案 B)。 背景:2026-08-21 实盘选股挂死+涨跌停过滤失效,根因都是「回测 provider (LocalUnifiedProvider)有、实盘 provider(SanguoMiniQmtProvider)无」的方法缺口 (累计 5 个洞)。ff05207 加钉死测试,但当时 CI 只跑 tests/data_platform → 钉死 虚标(issue #35)。2026-08-22 起 CI 扩跑 tests/portfolio(原 13 个 Mac 环境失败 已被依赖治理顺带清零,实测 440 绿 1.74s),本文件成为钉死的**唯一**版本—— 原先两处冗余已删:tests/portfolio/test_provider.py 内旧版(挂模块级 requires_bullet_trade mark,conftest 会在 bullet_trade 缺失时自动 skip=牙齿弱) 和 tests/data_platform/test_provider_method_parity.py 复制版(方案 A 过渡)。 牙齿自检:bullet_trade 不可用直接 FAIL(而非 skip)——skip 会让钉死在环境 劣化时无声失效,重蹈 issue #35。本文件故意**不打** requires_bullet_trade mark, conftest 的自动 skip 对它不适用。 """ import pathlib import re def test_method_surface_no_gap_left(): """unified 全部公共方法在实盘 provider(+MiniQMTProvider base)都有。""" try: from sanguo_portfolio import SanguoMiniQmtProvider from bullet_trade.data.providers.miniqmt import MiniQMTProvider except ImportError as exc: import pytest pytest.fail( f"方法面钉死测试无法执行(缺依赖 {exc})——CI venv310 必须装 " f"bullet_trade,否则钉死虚标(issue #35 重演)") base_dir = pathlib.Path(__file__).resolve().parents[2] uni_src = (base_dir / "sanguo_portfolio/providers/local_unified_provider.py" ).read_text(encoding="utf-8") uni_methods = set(re.findall(r"^\s{4}def ([a-z]\w+)\(", uni_src, re.M)) provider = SanguoMiniQmtProvider.__dict__ base_methods = set( n for n, v in vars(MiniQMTProvider).items() if callable(v) and not n.startswith("__")) missing = sorted( m for m in uni_methods if not m.startswith("_") and m not in provider and m not in base_methods) assert missing == [], f"回测有实盘无: {missing}"