From 373bcb2a6804dcbea78bf22cf83234eb29621de9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=BF=E4=BA=91=E7=A7=8B=E6=9C=88?= <15273589815@163.com> Date: Mon, 14 Sep 2026 00:02:35 +0800 Subject: [PATCH] =?UTF-8?q?fix(test):=20=E8=A1=A5=20FakeSession.scalar=20?= =?UTF-8?q?=E6=A1=A9=EF=BC=8C=E4=BF=AE=E5=A4=8D=E5=90=88=E5=B9=B6=E8=BF=9B?= =?UTF-8?q?=E6=9D=A5=E7=9A=84=2015=20=E4=B8=AA=E7=BA=A2=E7=81=AF=E7=94=A8?= =?UTF-8?q?=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 组员的 `2a3146e`("增加风控列表总数")在 `fund_query_repository.fetch_page` 里新增了 一次 `await self.session.scalar(select(func.count())...)` 来返回 `total`,但 `tests/unit/repository/test_fund_query_repository.py` 的 `FakeSession` 只有 `execute`, 于是该文件**15 个用例全部**挂在: AttributeError: 'FakeSession' object has no attribute 'scalar' ## 改动 给 `FakeSession` 加 `scalar`: - **返回值取 `len(_rows)`**。这些用例没有一处断言 `total`(只校验 `has_more` / `next_offset` 与生成的 SQL),返回非负整数即可;`_rows` 是带 `limit+1` 的当页结果, 所以它**不是真实总数** —— 将来若要断言 total,需给这个桩加显式参数。 - **不写入 `statements`**。`last_sql` 取的是 `statements[-1]`,而有用例断言的是 **分页查询**的 SQL(LIMIT / ORDER BY / 过滤条件)。第一版实现把 count 语句也 append 了进去,`last_sql` 随即指向 count 语句,4 个用例的断言集体落空 (实测:15 failed → 4 failed → 0)。count 语句改记在 `count_statements` 里备查。 验证:`test_fund_query_repository.py` 18 passed;unit+contract **1397 passed**; ruff 通过;e2e 冒烟 40/40。 --- .../repository/test_fund_query_repository.py | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/unit/repository/test_fund_query_repository.py b/tests/unit/repository/test_fund_query_repository.py index 493494f..ac835db 100644 --- a/tests/unit/repository/test_fund_query_repository.py +++ b/tests/unit/repository/test_fund_query_repository.py @@ -51,11 +51,34 @@ class FakeSession: def __init__(self, rows: list[dict[str, Any]] | None = None) -> None: self._rows = rows if rows is not None else [] self.statements: list[Any] = [] + #: `scalar()` 收到的统计语句单独存放,**不进 `statements`** —— 见 `scalar` 的说明。 + self.count_statements: list[Any] = [] async def execute(self, statement: Any) -> FakeResult: self.statements.append(statement) return FakeResult(self._rows) + async def scalar(self, statement: Any) -> Any: + """`total` 统计用的桩。 + + 实现层(`fetch_page`)新增了一次 `select(func.count())` 来返回总数 + ("增加风控列表总数"那个需求),这里补上对应方法 —— 原先的假 Session 只有 + `execute`,于是 15 个用例一起挂在 + `AttributeError: 'FakeSession' object has no attribute 'scalar'` 上。 + + 返回值不影响任何断言:这些用例只校验 `has_more` / `next_offset` 与生成的 SQL, + 没有一处断言 `total`。这里返回 `len(_rows)` 只是让实现层的 `int(... or 0)` + 拿到一个非负整数;**它不是真实总数**(`_rows` 是带 `limit+1` 的当页查询结果)。 + 将来若要断言 total,需要让这个桩接收显式的 total 参数。 + + ⚠️ **不写入 `statements`**:那些用例的 `last_sql` 断言的是**分页查询**的 SQL + (LIMIT / ORDER BY / 过滤条件)。若把 count 语句也追加进去,`last_sql` 就会指向 + count 语句,4 个别例的断言会集体落空(实测就是如此)。所以 count 语句单独记在 + `count_statements` 里备查。 + """ + self.count_statements.append(statement) + return len(self._rows) + @property def last_sql(self) -> str: return flat_sql(self.statements[-1])