Files
PolyLoop/src/polyloop/testing/_plugin.py
T
iomgaa 1fac387e75 feat(testing): 契约套件搬进 polyloop.testing 随包发布,五套全部接上实现
tests/ 不进 wheel,所以那套被 CLAUDE.md §0 称作「任何新适配器的准入标准」的用例,第一个
下游根本拿不到。**接法同时换掉**:pytest 的 conftest 只沿被收集文件的目录链查找,装在
site-packages 里的测试模块看不见下游的 conftest,原来那个「在自己的 conftest 里覆盖同名
fixture」的接法在发布之后走不通。改成继承契约基类,下游的子类定义在自己的目录链上。

**搬的过程中发现这套准入标准从来没被执行过。** test_model_client.py 有四条用例调用
records.model_call(...),而工厂里根本没有这个方法——它没炸是因为那个 fixture 默认 skip。
五个接缝里只有存储那套被真跑过(15 条跳过里有 15 条是这四套)。

所以这个提交的另一半是让它真的跑起来。存储接两个实现(一份契约同时验多个实现,正是换接法
换来的);动作执行接注册表分发器,外加一个有真实等待点的替身,否则那条取消用例的断言半边
永远走不到;模型调用接网关适配器,落在 integration,它连的是真网关;决策解释与事件出口各
接一个测试替身——替身住在 tests/ 里不进 wheel,下游拿不到,所以不违反「库不带默认实现」,
判据是下游拿不拿得到。

**一并清掉两类坏用例。** 五条函数体只有 docstring、一个断言都没有却报 PASSED 的假绿——一个
准入标准里出现假绿比出现跳过糟得多,下游看到全绿会以为验过了。以及一条端口从没承诺过的
长度断言(len(history_text) <= len(reply.content)):压测的 AppWorld 场景为了迁就它,刻意
不补被复刻的实现真的会补的三个反引号,注释里写着「补一个字符就违约」。七条「这一层验不了」
统一成无条件 skip,理由字符串写全「承诺是什么/为什么验不了/你该在哪儿自己验」。

**发一个 pytest11 entry point,只为换回断言重写。** 契约模块不在下游的 python_files 里,
默认不被重写,于是一条契约失败时下游看到的是光秃秃的 AssertionError。不做的话没有任何东西
会报错,纯静默退化。实测过:editable 安装下 entry point 注册了但重写不生效(RECORD 里没有
包文件),要装真 wheel 才验得出来。
2026-08-27 03:59:16 -04:00

27 lines
1.7 KiB
Python

"""pytest 插件入口。它什么都不做,存在的理由全在这段话里。
`pyproject.toml` 的 `[project.entry-points.pytest11]` 指向这个模块。pytest 启动时会先扫一遍
所有声明了 `pytest11` 入口的发行包,把它们的每一个 `.py` 文件标记为**断言可重写**,然后才
加载插件本身。换回来的就是这个标记:契约模块不在下游的 `python_files` 匹配范围里,默认不被
重写,于是一条契约用例失败时下游看到的是光秃秃的 `AssertionError`——没有等号两边的值,没有
差异摘要。
**删掉这个模块不会有任何东西报错**,下游只会觉得这套契约的报错难读,而且永远不会知道自己
少了什么。这是一次纯静默的退化,所以它值得一个只有 docstring 的模块。
**这个模块只 import pytest 与标准库。** 不 import 任何存储实现、不 import `polyloop.session`、
不 import `polyloop.adapters`——最后一条尤其硬:`adapters` 会把网关连同它的 provider 目录一起
拉起来,而 pytest 自动加载插件是那条依赖规则的一条新触发路径。这条边界不靠自觉,
import-linter 的分层契约与「除 testing 外一切禁止 import pytest」两条契约把它钉住。
**这里不接管事件循环**,理由见 `research-wiki/design/0014-contract-suite-distribution.md`
决策三末尾:下游的异步 fixture 在它自己的循环里创建,库另开一个循环会让那些 asyncio 对象
跨循环,而跨循环的对象炸得很难查。
"""
import pytest
def pytest_configure(config: pytest.Config) -> None:
"""空钩子。断言重写在 pytest 加载插件之前就按发行包做完了,这里没有要补的事。"""