fix: 测试添加 cv2 可用性检测,mock 环境下 skip
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 6s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 24s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 28s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 52s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 1m26s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 1m44s
CI/CD Pipeline / Validate - Style (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Security (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been cancelled
CI/CD Pipeline / Check push changed paths (pull_request) Has been skipped
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 2s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 6s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 24s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 28s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 52s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 1m26s
CI/CD Pipeline / Validate - Python (mypy + alembic) (pull_request) Successful in 1m44s
CI/CD Pipeline / Validate - Style (pull_request) Has been cancelled
CI/CD Pipeline / Validate - Security (pull_request) Has been cancelled
CI/CD Pipeline / Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
AI Code Review / AI Code Review (pull_request) Has been cancelled
PR Automation / Auto Approve on CI Green (pull_request) Has been cancelled
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been cancelled
This commit is contained in:
@@ -10,13 +10,38 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import inspect
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
|
||||
def _cv2_available() -> bool:
|
||||
"""检测 cv2 是否真实可用(非 mock)."""
|
||||
try:
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
||||
if not hasattr(cv2, "Laplacian") or not inspect.isroutine(cv2.Laplacian):
|
||||
return False
|
||||
if "mock" in str(type(cv2.Laplacian)).lower():
|
||||
return False
|
||||
# 实际调用测试
|
||||
_test = np.zeros((2, 2, 3), dtype=np.uint8)
|
||||
_result = cv2.cvtColor(_test, cv2.COLOR_BGR2GRAY)
|
||||
return isinstance(_result, np.ndarray)
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
HAS_CV2 = _cv2_available()
|
||||
requires_cv2 = pytest.mark.skipif(not HAS_CV2, reason="cv2 不可用或是 mock 对象")
|
||||
|
||||
|
||||
class TestScoreFrame:
|
||||
"""score_frame 单元测试."""
|
||||
|
||||
@requires_cv2
|
||||
def test_clear_image_high_score(self):
|
||||
"""清晰、亮度适中、色彩丰富的图像应得高分."""
|
||||
# 创建一个清晰的渐变图像(色彩丰富、亮度适中)
|
||||
@@ -30,6 +55,7 @@ class TestScoreFrame:
|
||||
score = score_frame(img)
|
||||
assert 50.0 <= score <= 100.0, f"清晰图像应得高分,实际: {score}"
|
||||
|
||||
@requires_cv2
|
||||
def test_blurry_image_low_clarity(self):
|
||||
"""模糊图像的清晰度分数应较低."""
|
||||
# 纯色图像(无高频细节)
|
||||
@@ -41,6 +67,7 @@ class TestScoreFrame:
|
||||
# 纯色图像清晰度为 0,亮度满分 30,色彩为 0
|
||||
assert score <= 35.0, f"模糊图像应低分,实际: {score}"
|
||||
|
||||
@requires_cv2
|
||||
def test_dark_image_low_brightness(self):
|
||||
"""过暗图像应扣分."""
|
||||
# 全黑图像
|
||||
@@ -52,6 +79,7 @@ class TestScoreFrame:
|
||||
# 全黑:清晰度 0,亮度 0,色彩 0
|
||||
assert score <= 5.0, f"全黑图像应接近 0 分,实际: {score}"
|
||||
|
||||
@requires_cv2
|
||||
def test_bright_image_low_brightness(self):
|
||||
"""过亮图像应扣分."""
|
||||
# 全白图像
|
||||
@@ -63,6 +91,7 @@ class TestScoreFrame:
|
||||
# 全白:清晰度 0(无边缘),亮度偏低(偏离 130),色彩 0
|
||||
assert score <= 20.0, f"全白图像应较低分,实际: {score}"
|
||||
|
||||
@requires_cv2
|
||||
def test_medium_brightness_full_score(self):
|
||||
"""亮度在 80~180 区间应得亮度满分."""
|
||||
# 中等亮度灰色
|
||||
@@ -77,6 +106,7 @@ class TestScoreFrame:
|
||||
# 亮度应在舒适区间
|
||||
assert score >= 25.0, f"中等亮度图像应有一定分数,实际: {score}"
|
||||
|
||||
@requires_cv2
|
||||
def test_colorful_image_high_color_score(self):
|
||||
"""色彩丰富的图像应得高色彩分."""
|
||||
# 彩虹渐变
|
||||
@@ -98,6 +128,7 @@ class TestScoreFrame:
|
||||
assert score_frame(np.array([])) == 0.0
|
||||
assert score_frame(None) == 0.0
|
||||
|
||||
@requires_cv2
|
||||
def test_score_range(self):
|
||||
"""评分必须在 0~100 范围内."""
|
||||
from packages.shared.cover_frame_scorer import score_frame
|
||||
@@ -112,6 +143,7 @@ class TestScoreFrame:
|
||||
class TestScoreFrames:
|
||||
"""score_frames 批量评分测试."""
|
||||
|
||||
@requires_cv2
|
||||
def test_returns_sorted_by_score(self):
|
||||
"""返回结果应按分数从高到低排序."""
|
||||
from packages.shared.cover_frame_scorer import score_frames
|
||||
@@ -132,6 +164,7 @@ class TestScoreFrames:
|
||||
assert scored[0]["score"] >= scored[1]["score"]
|
||||
assert scored[1]["score"] >= scored[2]["score"]
|
||||
|
||||
@requires_cv2
|
||||
def test_all_have_score_field(self):
|
||||
"""每个帧都应该有 score 字段."""
|
||||
from packages.shared.cover_frame_scorer import score_frames
|
||||
@@ -155,6 +188,7 @@ class TestScoreFrames:
|
||||
class TestSelectBestFrame:
|
||||
"""select_best_frame 测试."""
|
||||
|
||||
@requires_cv2
|
||||
def test_returns_highest_score(self):
|
||||
"""返回分数最高的帧."""
|
||||
from packages.shared.cover_frame_scorer import select_best_frame
|
||||
@@ -174,6 +208,7 @@ class TestSelectBestFrame:
|
||||
|
||||
assert select_best_frame([]) is None
|
||||
|
||||
@requires_cv2
|
||||
def test_single_frame(self):
|
||||
"""单帧直接返回."""
|
||||
from packages.shared.cover_frame_scorer import select_best_frame
|
||||
|
||||
Reference in New Issue
Block a user