refactor: split monolithic phase tests into per-module test files
- rename test_admin_phase4.py -> test_admin.py, test_search.py -> test_searcher.py - split test_phase5.py into test_cleaner, test_embedder, test_image_extractor, test_pages - move schema tests from test_summarizer.py into dedicated test_schemas.py - add sample_papers_range and sample_papers_with_summary fixtures in conftest - update .gitignore to exclude all of data/
This commit is contained in:
@@ -0,0 +1,224 @@
|
||||
"""页面路由测试 — detail、trends、compare、graceful degradation。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import date
|
||||
from unittest.mock import patch as upatch
|
||||
|
||||
import pytest
|
||||
|
||||
from app.config import settings
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
# Detail 页 & 相似论文
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
|
||||
class TestDetailPage:
|
||||
"""论文详情页测试。"""
|
||||
|
||||
def test_detail_page_renders(self, client, sample_papers_with_summary):
|
||||
"""详情页正常渲染。"""
|
||||
resp = client.get("/paper/2401.20001")
|
||||
assert resp.status_code == 200
|
||||
assert "测试论文" in resp.text or "Test Paper" in resp.text
|
||||
|
||||
def test_detail_page_not_found(self, client):
|
||||
"""不存在的论文返回 404。"""
|
||||
resp = client.get("/paper/nonexistent.99999")
|
||||
assert resp.status_code == 404
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
# Similar API(详情页内联)
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
|
||||
class TestDetailSimilarPapers:
|
||||
"""详情页相似论文模块测试(CHROMA 关闭时的降级行为)。"""
|
||||
|
||||
def test_detail_page_renders_with_similar(self, client, sample_papers_with_summary):
|
||||
"""详情页正常渲染(含相似论文模块)。"""
|
||||
resp = client.get("/paper/2401.20001")
|
||||
assert resp.status_code == 200
|
||||
assert "测试论文" in resp.text or "Test Paper" in resp.text
|
||||
|
||||
def test_detail_page_not_found_similar(self, client):
|
||||
"""不存在的论文返回 404。"""
|
||||
resp = client.get("/paper/nonexistent.99999")
|
||||
assert resp.status_code == 404
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
# Trends Dashboard
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
|
||||
class TestTrendsDashboard:
|
||||
"""趋势看板测试。"""
|
||||
|
||||
def test_trends_page_renders(self, client, sample_papers_with_summary):
|
||||
"""趋势看板页面正常渲染。"""
|
||||
resp = client.get("/trends")
|
||||
assert resp.status_code == 200
|
||||
assert "趋势看板" in resp.text
|
||||
assert "chart" in resp.text.lower() or "Chart" in resp.text
|
||||
|
||||
def test_trends_api_returns_data(self, client, sample_papers_with_summary):
|
||||
"""趋势 API 返回正确数据结构。"""
|
||||
resp = client.get("/api/stats/trends")
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
|
||||
assert "daily_counts" in data
|
||||
assert "top_tags" in data
|
||||
assert "upvotes_dist" in data
|
||||
assert "summary_completion" in data
|
||||
|
||||
assert isinstance(data["daily_counts"], list)
|
||||
assert isinstance(data["top_tags"], list)
|
||||
assert isinstance(data["upvotes_dist"], list)
|
||||
assert isinstance(data["summary_completion"], list)
|
||||
|
||||
def test_trends_api_daily_counts(self, client, sample_papers_with_summary):
|
||||
"""每日论文数量数据正确。"""
|
||||
# 使用测试数据的日期范围
|
||||
with upatch("app.services.trends.date") as mock_date:
|
||||
mock_date.today.return_value = date(2024, 1, 20)
|
||||
mock_date.side_effect = lambda *a, **kw: date(*a, **kw)
|
||||
|
||||
resp = client.get("/api/stats/trends")
|
||||
data = resp.json()
|
||||
assert len(data["daily_counts"]) == 5
|
||||
for item in data["daily_counts"]:
|
||||
assert "date" in item
|
||||
assert "count" in item
|
||||
assert item["count"] == 1
|
||||
|
||||
def test_trends_api_top_tags(self, client, sample_papers_with_summary):
|
||||
"""热门标签数据正确。"""
|
||||
resp = client.get("/api/stats/trends")
|
||||
data = resp.json()
|
||||
tags = {t["tag"]: t["count"] for t in data["top_tags"]}
|
||||
assert "NLP" in tags
|
||||
assert tags["NLP"] == 5 # 所有论文都有 NLP
|
||||
|
||||
def test_trends_api_summary_completion(self, client, sample_papers_with_summary):
|
||||
"""总结完成率数据正确。"""
|
||||
resp = client.get("/api/stats/trends")
|
||||
data = resp.json()
|
||||
statuses = {s["status"]: s["count"] for s in data["summary_completion"]}
|
||||
assert "done" in statuses
|
||||
assert statuses["done"] == 4 # 4 篇已完成
|
||||
|
||||
def test_trends_empty_db(self, client):
|
||||
"""无数据时不崩溃。"""
|
||||
resp = client.get("/api/stats/trends")
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert data["daily_counts"] == []
|
||||
assert data["top_tags"] == []
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
# Compare Page
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
|
||||
class TestComparePage:
|
||||
"""论文对比页测试。"""
|
||||
|
||||
def test_compare_page_no_ids(self, client):
|
||||
"""无 ID 时显示输入表单。"""
|
||||
resp = client.get("/compare")
|
||||
assert resp.status_code == 200
|
||||
assert "对比" in resp.text
|
||||
|
||||
def test_compare_page_with_ids(self, client, sample_papers_with_summary):
|
||||
"""对比多篇论文正常渲染。"""
|
||||
resp = client.get("/compare?ids=2401.20001,2401.20002")
|
||||
assert resp.status_code == 200
|
||||
assert "2401.20001" in resp.text
|
||||
assert "2401.20002" in resp.text
|
||||
# 应包含对比字段
|
||||
assert "一句话摘要" in resp.text
|
||||
assert "研究问题" in resp.text
|
||||
|
||||
def test_compare_page_max_5(self, client, sample_papers_with_summary):
|
||||
"""最多 5 篇。"""
|
||||
ids = "2401.20001,2401.20002,2401.20003,2401.20004,2401.20005"
|
||||
resp = client.get(f"/compare?ids={ids}")
|
||||
assert resp.status_code == 200
|
||||
|
||||
def test_compare_page_over_5_truncates(self, client, sample_papers_with_summary):
|
||||
"""超过 5 篇截断。"""
|
||||
ids = "2401.20001,2401.20002,2401.20003,2401.20004,2401.20005,2401.20006"
|
||||
resp = client.get(f"/compare?ids={ids}")
|
||||
assert resp.status_code == 200
|
||||
|
||||
def test_compare_page_invalid_ids(self, client):
|
||||
"""无效 ID 时显示空结果。"""
|
||||
resp = client.get("/compare?ids=nonexistent.99999")
|
||||
assert resp.status_code == 200
|
||||
|
||||
def test_compare_page_shows_no_summary_placeholder(self, client, sample_papers_with_summary):
|
||||
"""无总结的论文显示占位文本。"""
|
||||
# 2401.20005 没有 summary(status=pending)
|
||||
resp = client.get("/compare?ids=2401.20005")
|
||||
assert resp.status_code == 200
|
||||
assert "暂无总结" in resp.text
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
# Nav Bar
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
|
||||
class TestNavBar:
|
||||
"""导航栏测试。"""
|
||||
|
||||
def test_nav_includes_trends_link(self, client):
|
||||
"""导航栏应包含趋势链接。"""
|
||||
resp = client.get("/search")
|
||||
assert resp.status_code == 200
|
||||
assert "/trends" in resp.text
|
||||
|
||||
def test_nav_includes_compare_implicitly(self, client):
|
||||
"""compare 页面可访问。"""
|
||||
resp = client.get("/compare")
|
||||
assert resp.status_code == 200
|
||||
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
# Graceful Degradation(CHROMA_ENABLED=false)
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
|
||||
class TestGracefulDegradation:
|
||||
"""CHROMA_ENABLED=false 时优雅降级测试。"""
|
||||
|
||||
def test_search_works_without_chroma(self, client, monkeypatch, sample_papers_with_summary):
|
||||
"""CHROMA 关闭时 FTS5 搜索正常工作。"""
|
||||
monkeypatch.setattr(settings, "CHROMA_ENABLED", False)
|
||||
resp = client.get("/search?q=Test")
|
||||
assert resp.status_code == 200
|
||||
assert "Test Paper" in resp.text or "测试论文" in resp.text
|
||||
|
||||
def test_detail_works_without_chroma(self, client, monkeypatch, sample_papers_with_summary):
|
||||
"""CHROMA 关闭时详情页正常工作。"""
|
||||
monkeypatch.setattr(settings, "CHROMA_ENABLED", False)
|
||||
resp = client.get("/paper/2401.20001")
|
||||
assert resp.status_code == 200
|
||||
|
||||
def test_trends_works_without_chroma(self, client, monkeypatch, sample_papers_with_summary):
|
||||
"""CHROMA 关闭时趋势看板正常工作。"""
|
||||
monkeypatch.setattr(settings, "CHROMA_ENABLED", False)
|
||||
resp = client.get("/trends")
|
||||
assert resp.status_code == 200
|
||||
|
||||
def test_compare_works_without_chroma(self, client, monkeypatch, sample_papers_with_summary):
|
||||
"""CHROMA 关闭时对比页正常工作。"""
|
||||
monkeypatch.setattr(settings, "CHROMA_ENABLED", False)
|
||||
resp = client.get("/compare?ids=2401.20001,2401.20002")
|
||||
assert resp.status_code == 200
|
||||
Reference in New Issue
Block a user