We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Xeron2000/viral-shorts'
If you have feedback or need assistance with the MCP directory API, please join our Discord server
"""YouTube 模块单元测试"""
import pytest
from datetime import datetime, timezone, timedelta
from src.models.video import VideoData
from src.youtube.analyzer import ViralAnalyzer
class TestViralAnalyzer:
"""爆款分析器测试"""
def test_calculate_hours_since_publish(self):
"""测试发布时长计算"""
# 2 小时前发布
published_at = datetime.now(timezone.utc) - timedelta(hours=2)
hours = ViralAnalyzer.calculate_hours_since_publish(published_at)
assert 1.9 <= hours <= 2.1 # 允许小误差
def test_calculate_vph(self):
"""测试 VPH 计算"""
# 10,000 播放量,2 小时
vph = ViralAnalyzer.calculate_vph(10000, 2)
assert vph == 5000
# 边界情况:0 小时
vph = ViralAnalyzer.calculate_vph(1000, 0)
assert vph == 10000 # 至少算作 0.1 小时
def test_calculate_engagement_rate(self):
"""测试互动率计算"""
# 1000 播放,50 点赞,10 评论
rate = ViralAnalyzer.calculate_engagement_rate(1000, 50, 10)
assert rate == 6.0 # (50+10)/1000 * 100 = 6%
# 边界情况:0 播放
rate = ViralAnalyzer.calculate_engagement_rate(0, 10, 5)
assert rate == 0.0
def test_calculate_viral_score(self):
"""测试爆款指数计算"""
# VPH=5000, 2小时前, 互动率=5%
score = ViralAnalyzer.calculate_viral_score(5000, 2, 5)
# 时效权重 = 1/(2+1) = 0.333
# 互动权重 = 1 + (5/100*10) = 1.5
# score = 5000 * 0.333 * 1.5 ≈ 2500
assert 2400 <= score <= 2600
def test_categorize_potential(self):
"""测试潜力等级分类"""
assert "超级爆款" in ViralAnalyzer.categorize_potential(15000)
assert "高潜力" in ViralAnalyzer.categorize_potential(6000)
assert "潜力视频" in ViralAnalyzer.categorize_potential(2000)
assert "普通视频" in ViralAnalyzer.categorize_potential(500)
def test_analyze_video(self):
"""测试视频分析"""
# 创建测试视频
video = VideoData(
video_id="test123",
title="测试视频",
channel_name="测试频道",
channel_id="channel123",
views=10000,
likes=500,
comments=100,
published_at=datetime.now(timezone.utc) - timedelta(hours=2),
duration="PT30S",
url="https://youtube.com/shorts/test123"
)
# 分析视频
analyzed = ViralAnalyzer.analyze_video(video)
# 验证指标已填充
assert analyzed.vph > 0
assert analyzed.engagement_rate > 0
assert analyzed.viral_score > 0
assert analyzed.hours_since_publish > 0
def test_rank_videos(self):
"""测试视频排序"""
videos = [
VideoData(
video_id=f"test{i}",
title=f"视频{i}",
channel_name="频道",
channel_id="ch1",
views=1000,
likes=10,
comments=5,
published_at=datetime.now(timezone.utc),
duration="PT30S",
url=f"https://youtube.com/shorts/test{i}",
viral_score=float(i * 100)
)
for i in range(5)
]
ranked = ViralAnalyzer.rank_videos(videos)
# 验证降序排列
assert ranked[0].viral_score == 400
assert ranked[-1].viral_score == 0
def test_filter_by_vph(self):
"""测试 VPH 筛选"""
videos = [
VideoData(
video_id=f"test{i}",
title=f"视频{i}",
channel_name="频道",
channel_id="ch1",
views=1000,
likes=10,
comments=5,
published_at=datetime.now(timezone.utc),
duration="PT30S",
url=f"https://youtube.com/shorts/test{i}",
vph=float(i * 1000)
)
for i in range(5)
]
filtered = ViralAnalyzer.filter_by_vph(videos, 2000)
# 应该只保留 VPH >= 2000 的视频
assert len(filtered) == 3 # vph=2000, 3000, 4000
assert all(v.vph >= 2000 for v in filtered)
class TestVideoData:
"""视频数据模型测试"""
def test_to_markdown_row(self):
"""测试 Markdown 行生成"""
video = VideoData(
video_id="test123",
title="测试视频标题",
channel_name="测试频道",
channel_id="ch1",
views=10000,
likes=500,
comments=100,
published_at=datetime.now(timezone.utc),
duration="PT30S",
url="https://youtube.com/shorts/test123",
vph=5000,
engagement_rate=6.0,
viral_score=2500,
hours_since_publish=2.0
)
row = video.to_markdown_row()
assert "测试视频标题" in row
assert "测试频道" in row
assert "10,000" in row
assert "5,000" in row
assert "6.00%" in row
assert "2,500" in row
def test_markdown_header(self):
"""测试 Markdown 表头"""
header = VideoData.markdown_header()
assert "标题" in header
assert "VPH" in header
assert "互动率" in header
assert "爆款指数" in header
if __name__ == "__main__":
pytest.main([__file__, "-v"])