- 实现查询API (query.py): 支持star_id/unique_id/nickname三种查询方式 - 实现计算模块 (calculator.py): CPM/自然搜索UV/搜索成本计算 - 实现品牌API集成 (brand_api.py): 批量并发调用,10并发限制 - 实现导出服务 (export_service.py): Excel/CSV导出 - 前端组件: QueryForm/ResultTable/ExportButton - 主页面集成: 支持6种页面状态 - 测试: 44个测试全部通过,覆盖率88% Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
100 lines
3.8 KiB
Python
100 lines
3.8 KiB
Python
import pytest
|
|
from app.services.calculator import (
|
|
calculate_natural_cpm,
|
|
calculate_natural_search_uv,
|
|
calculate_natural_search_cost,
|
|
calculate_metrics,
|
|
)
|
|
|
|
|
|
class TestCalculator:
|
|
"""Tests for calculator functions."""
|
|
|
|
def test_calculate_natural_cpm_normal(self):
|
|
"""Test normal CPM calculation."""
|
|
result = calculate_natural_cpm(10000.0, 100000)
|
|
assert result == 100.0 # 10000 / 100000 * 1000 = 100
|
|
|
|
def test_calculate_natural_cpm_zero_play(self):
|
|
"""Test CPM with zero plays returns None."""
|
|
result = calculate_natural_cpm(10000.0, 0)
|
|
assert result is None
|
|
|
|
def test_calculate_natural_cpm_decimal(self):
|
|
"""Test CPM returns 2 decimal places."""
|
|
result = calculate_natural_cpm(1234.56, 50000)
|
|
assert result == 24.69 # round(1234.56 / 50000 * 1000, 2)
|
|
|
|
def test_calculate_natural_search_uv_normal(self):
|
|
"""Test normal search UV calculation."""
|
|
result = calculate_natural_search_uv(100000, 150000, 500)
|
|
expected = round((100000 / 150000) * 500, 2)
|
|
assert result == expected
|
|
|
|
def test_calculate_natural_search_uv_zero_total(self):
|
|
"""Test search UV with zero total plays returns None."""
|
|
result = calculate_natural_search_uv(100000, 0, 500)
|
|
assert result is None
|
|
|
|
def test_calculate_natural_search_uv_zero_natural(self):
|
|
"""Test search UV with zero natural plays."""
|
|
result = calculate_natural_search_uv(0, 150000, 500)
|
|
assert result == 0.0
|
|
|
|
def test_calculate_natural_search_cost_normal(self):
|
|
"""Test normal search cost calculation."""
|
|
result = calculate_natural_search_cost(10000.0, 333.33)
|
|
assert result == 30.0 # round(10000 / 333.33, 2)
|
|
|
|
def test_calculate_natural_search_cost_zero_uv(self):
|
|
"""Test search cost with zero UV returns None."""
|
|
result = calculate_natural_search_cost(10000.0, 0)
|
|
assert result is None
|
|
|
|
def test_calculate_natural_search_cost_none_uv(self):
|
|
"""Test search cost with None UV returns None."""
|
|
result = calculate_natural_search_cost(10000.0, None)
|
|
assert result is None
|
|
|
|
def test_calculate_metrics_all_normal(self):
|
|
"""Test calculate_metrics with all normal values."""
|
|
result = calculate_metrics(
|
|
estimated_video_cost=10000.0,
|
|
natural_play_cnt=100000,
|
|
total_play_cnt=150000,
|
|
after_view_search_uv=500,
|
|
)
|
|
|
|
assert result["estimated_natural_cpm"] == 100.0
|
|
assert result["estimated_natural_search_uv"] == round((100000 / 150000) * 500, 2)
|
|
expected_cost = round(10000.0 / result["estimated_natural_search_uv"], 2)
|
|
assert result["estimated_natural_search_cost"] == expected_cost
|
|
|
|
def test_calculate_metrics_zero_plays(self):
|
|
"""Test calculate_metrics with zero plays."""
|
|
result = calculate_metrics(
|
|
estimated_video_cost=10000.0,
|
|
natural_play_cnt=0,
|
|
total_play_cnt=0,
|
|
after_view_search_uv=500,
|
|
)
|
|
|
|
assert result["estimated_natural_cpm"] is None
|
|
assert result["estimated_natural_search_uv"] is None
|
|
assert result["estimated_natural_search_cost"] is None
|
|
|
|
def test_calculate_metrics_partial_zero(self):
|
|
"""Test calculate_metrics with partial zero values."""
|
|
result = calculate_metrics(
|
|
estimated_video_cost=10000.0,
|
|
natural_play_cnt=100000,
|
|
total_play_cnt=0, # Zero total plays
|
|
after_view_search_uv=500,
|
|
)
|
|
|
|
# CPM can still be calculated
|
|
assert result["estimated_natural_cpm"] == 100.0
|
|
# But search UV and cost cannot
|
|
assert result["estimated_natural_search_uv"] is None
|
|
assert result["estimated_natural_search_cost"] is None
|