diff --git a/tests/unit/test_smart_match.py b/tests/unit/test_smart_match.py index 0a31b4c34..97abb2e70 100755 --- a/tests/unit/test_smart_match.py +++ b/tests/unit/test_smart_match.py @@ -1,5 +1,6 @@ """Tests for packages/domain/smart_match.py — 统一智能选素材算法。""" +import random from dataclasses import dataclass, field from datetime import datetime, timedelta, timezone from typing import Any @@ -7,6 +8,7 @@ from typing import Any import pytest from packages.domain.smart_match import ( + SCORE_RANDOM_NOISE_MAX, SmartMatchResult, _diversity_select, _duration_bucket, @@ -46,6 +48,22 @@ class FakeAsset: NOW = datetime(2026, 8, 5, 12, 0, 0, tzinfo=timezone.utc) +class _ZeroNoiseRandom(random.Random): + """零噪声随机源:uniform(0, NOISE_MAX) 恒返回 0,使「按评分降序」类断言确定可复现。 + + smart_select_assets 生产环境注入随机噪声(同分素材每次选出不同组合,#1743); + 验证纯评分排序的单测用本随机源消除排序随机性。 + """ + + def uniform(self, a, b): + if a == 0.0 and b == SCORE_RANDOM_NOISE_MAX: + return 0.0 + return super().uniform(a, b) + + +_ZERO_NOISE = _ZeroNoiseRandom(0) + + # ── score_asset tests ──────────────────────────────────────────────────────── @@ -185,7 +203,7 @@ class TestSmartSelectAssets: FakeAsset(id="high", quality_score=95, duration=15), FakeAsset(id="mid", quality_score=60, duration=15), ] - results = smart_select_assets(assets) + results = smart_select_assets(assets, rng=_ZERO_NOISE) scores = [r.score for r in results] assert scores == sorted(scores, reverse=True) assert results[0].asset.id == "high" @@ -234,7 +252,7 @@ class TestSmartSelectAssets: FakeAsset(id="img1", mime_type="image/jpeg", quality_score=90, duration=None), FakeAsset(id="img2", mime_type="image/png", quality_score=70, duration=None), ] - results = smart_select_assets(assets, kind="image") + results = smart_select_assets(assets, kind="image", rng=_ZERO_NOISE) assert len(results) == 2 assert results[0].asset.id == "img1" diff --git a/tests/unit/test_smart_match_fallback.py b/tests/unit/test_smart_match_fallback.py index 0e9f5f236..d31fbb88b 100644 --- a/tests/unit/test_smart_match_fallback.py +++ b/tests/unit/test_smart_match_fallback.py @@ -155,7 +155,9 @@ class TestSmartMatchAvailabilityFallback: project = Project(id="proj-1", name="Test", owner_user_id="user-1") assets = [ _video_asset("top-exhausted.mp4", quality=100, used_ranges=_exhausted_ranges(15)), - _video_asset("second-fresh.mp4", quality=40, used_ranges=None), + # second 质量分显著高于 third(质量项差 (90-30)*0.4=24 > 噪声上限 20), + # 排除耗尽素材后 second 稳定排首位回补(噪声不影响大分差排名) + _video_asset("second-fresh.mp4", quality=90, used_ranges=None), _video_asset("third-fresh.mp4", quality=30, used_ranges=None), ] repo = _StubAssetRepo(assets)