Files
easy_tdx_max/tests/unit/test_board_members_pagination.py
Justin Gu 7456f81c80 fix: 板块成分股/排行报价分页合并顺序颠倒 — 多页前插改按页序追加
BoardMembersQuotesCmd 分页合并曾用 batch + all_quotes 前插,而协议 start=0
返回排序后最前一页:成分股超过单页 80 只的板块(半导体 SH881319、
光学光电 SH881329、通信设备 SH881338 等)弹窗涨跌幅榜从第 81~100 名开头,
前 80 名被压到后面,肉眼即乱序;≤80 只的板块单页不受影响。

同步/异步 get_board_members 与 get_stock_quotes_list 共 4 处统一改为
按页序追加(all_quotes = all_quotes + batch),回归测试钉死多页合并顺序、
start 偏移推进与末页不足一页的终止行为。

注:test_ex_reconnect::test_all_retries_relogin_each_time 存量失败
(干净工作树同样失败),与本修复无关,另案处理。
2026-09-05 03:30:52 +08:00

104 lines
3.4 KiB
Python
Raw Permalink 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.
"""成分股/排行报价分页合并顺序回归测试。
真实 bugv1.32.x):BoardMembersQuotesCmd 分页合并曾用 ``batch + all_quotes``
前插,而协议 ``start=0`` 返回排序后**最前**的一页——多页时整表被按页倒序拼接:
成分股超过单页 80 只的板块(如半导体 SH881319),弹窗涨跌幅榜从第 81 名开头,
前 80 名被压到后面,肉眼即"乱序"。
本测试钉死:多页合并必须按请求顺序追加,且 start 偏移正确推进。
"""
from unittest.mock import patch
import pytest
from easy_tdx.mac.client import AsyncMacClient, MacClient
from easy_tdx.mac.enums import SortOrder, SortType
from easy_tdx.mac.models import MacQuoteField
_TOTAL = 100 # 超过单页 80,触发两页
def _make_rows(start: int, n: int) -> list[MacQuoteField]:
"""模拟服务器:按涨跌幅降序返回第 start..start+n 名。"""
def code(i: int) -> str:
return f"{600000 + i:06d}"
return [
MacQuoteField(
market=1,
code=code(i),
name=f"股{i}",
fields={"change_pct": 10.0 - i * 0.2},
)
for i in range(start, start + n)
]
def _fake_execute_factory(seen: list):
def fake_execute(cmd):
seen.append(cmd)
# 真实服务器按剩余行数返回(末页不足 page_size),模拟之
n = min(cmd._page_size, _TOTAL - cmd._start)
return _make_rows(cmd._start, n)
return fake_execute
def test_board_members_pages_appended_in_order():
"""get_board_members 多页合并按页序追加:第 0 行=第 1 名,第 80 行=第 81 名。"""
client = MacClient.__new__(MacClient)
seen: list = []
with patch.object(client, "_execute", side_effect=_fake_execute_factory(seen)):
df = client.get_board_members(
"881319",
count=_TOTAL,
sort_type=SortType.CHANGE_PCT,
sort_order=SortOrder.DESC,
)
assert len(df) == _TOTAL
assert df["code"].tolist() == [f"{600000 + i:06d}" for i in range(_TOTAL)]
# 两页:start 080 行)→ start 8020 行)
assert [c._start for c in seen] == [0, 80]
@pytest.mark.asyncio
async def test_board_members_async_pages_appended_in_order():
client = AsyncMacClient.__new__(AsyncMacClient)
seen: list = []
async def fake_execute(cmd):
seen.append(cmd)
return _make_rows(cmd._start, cmd._page_size)
with patch.object(client, "_execute", side_effect=fake_execute):
df = await client.get_board_members(
"881319",
count=_TOTAL,
sort_type=SortType.CHANGE_PCT,
sort_order=SortOrder.DESC,
)
assert df["code"].tolist() == [f"{600000 + i:06d}" for i in range(_TOTAL)]
assert [c._start for c in seen] == [0, 80]
def test_quotes_list_pages_appended_in_order():
"""get_stock_quotes_list(看板涨跌榜数据源)同样按页序追加。"""
client = MacClient.__new__(MacClient)
seen: list = []
with patch.object(client, "_execute", side_effect=_fake_execute_factory(seen)):
df = client.get_stock_quotes_list(
category=1, # Category.A
count=_TOTAL,
sort_type=SortType.CHANGE_PCT,
sort_order=SortOrder.DESC,
)
assert df["code"].tolist() == [f"{600000 + i:06d}" for i in range(_TOTAL)]
assert [c._start for c in seen] == [0, 80]