From fe79cd90c30dff38e3ac2d0d73eabbf4a600f515 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Mon, 31 Aug 2026 01:17:11 +0800 Subject: [PATCH] =?UTF-8?q?fix(test):=20test=5Fingest=5Fhevc=5Ftranscode?= =?UTF-8?q?=5Ftask=20=E6=A8=A1=E5=9D=97=E7=BA=A7=20mock=20=E7=94=A8?= =?UTF-8?q?=E5=90=8E=E6=B8=85=E7=90=86=EF=BC=8C=E4=BF=AE=E5=A4=8D=E8=B7=A8?= =?UTF-8?q?=E6=96=87=E4=BB=B6=20mock=20=E6=B1=A1=E6=9F=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 该文件在模块导入时向 sys.modules 注入 worker_app.db/celery_app/core.config、 video_processing.oss_helpers/thumbnail_generator 的 MagicMock(用于让 ingest 任务模块可导入),但注入后从不清理。pytest-xdist 下同一 worker 进程后续执行的测试文件会直接拿到 MagicMock 版本的模块——表现为 test_thumbnail_generator 的 50 个纯逻辑用例断言到 而失败 (执行顺序相关,故为非确定性失败)。 添加 module 作用域 autouse fixture,在本文件测试跑完后移除 mock 并 重新导入真实模块,与 test_dedup_pure/test_generated_video_creation_logic 的清理模式一致。 配套 #1563(test_dedup_engine 父包 mock 污染)。 --- tests/unit/test_ingest_hevc_transcode_task.py | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/unit/test_ingest_hevc_transcode_task.py b/tests/unit/test_ingest_hevc_transcode_task.py index a02a86bc1..41a795680 100644 --- a/tests/unit/test_ingest_hevc_transcode_task.py +++ b/tests/unit/test_ingest_hevc_transcode_task.py @@ -45,6 +45,38 @@ import pytest # noqa: E402 from worker_app.tasks import ingest as ingest_mod # noqa: E402 +# ── 模块级 mock 的清理 ───────────────────────────────────────────────────── +# 上方在模块导入时往 sys.modules 注入了 worker_app.* / video_processing.* +# 的 MagicMock(为了让 ingest_mod 可导入)。模块级注入不会随测试结束自动 +# 撤销,会污染同一 pytest 进程(含 xdist worker)后续执行的其他测试文件: +# 例如 test_thumbnail_generator.py 的纯逻辑用例会从 sys.modules 拿到 +# MagicMock 版本的 video_processing.thumbnail_generator,全部断言失败。 +# 用 module 作用域 autouse fixture 在本文件测试跑完后恢复真实模块。 +_MOCKED_MODULE_NAMES = ( + "worker_app.db", + "worker_app.core.config", + "worker_app.celery_app", + "video_processing.oss_helpers", + "video_processing.thumbnail_generator", +) + + +@pytest.fixture(scope="module", autouse=True) +def _restore_sys_modules_after_module_tests(): + yield + for _name in _MOCKED_MODULE_NAMES: + sys.modules.pop(_name, None) + # 重新导入真实模块,让后续测试文件拿到真实实现 + import importlib + + importlib.invalidate_caches() + for _name in ("video_processing.oss_helpers", "video_processing.thumbnail_generator"): + try: + importlib.import_module(_name) + except Exception: + pass + + class _FakeJobRepo: def __init__(self, db): self.initial_job = SimpleNamespace(