Files

96 lines
3.2 KiB
Python

"""
积分 Service 单元测试
=====================
不依赖数据库,仅测试配置加载、计费计算、充值档位等纯函数逻辑。
"""
import math
import pytest
from app.services import point_service as ps
class TestPointsConfig:
"""积分配置加载"""
def test_points_config_loaded(self) -> None:
assert "script" in ps.POINTS_CONFIG
assert "tts" in ps.POINTS_CONFIG
assert "video" in ps.POINTS_CONFIG
def test_get_chargeable_source_types(self) -> None:
types = ps.get_chargeable_source_types()
assert "script" in types
assert "tts" in types
# 免费业务不应出现在扣费列表
assert "caption" not in types
def test_get_recharge_options_returns_list(self) -> None:
options = ps.get_recharge_options()
assert isinstance(options, list)
if options:
assert "points" in options[0]
class TestCalculateCost:
"""后置计费计算"""
def test_fixed_cost(self) -> None:
assert ps._calculate_cost("script") == 5
assert ps._calculate_cost("polish") == 1
assert ps._calculate_cost("voice_clone") == 200
def test_free_cost(self) -> None:
free_types = [
key
for key, cfg in ps.POINTS_CONFIG.items()
if not key.startswith("_") and cfg.get("mode") == "free"
]
for source_type in free_types:
assert ps._calculate_cost(source_type) == 0
def test_unknown_source_type(self) -> None:
with pytest.raises(ValueError, match="未知的消费类型"):
ps._calculate_cost("not_exists")
def test_tts_duration_cost(self) -> None:
# tts: divisor=5,按 5 秒为单位计费
assert ps._calculate_cost("tts", {"seconds": 4}) == 1
assert ps._calculate_cost("tts", {"seconds": 5}) == 1
assert ps._calculate_cost("tts", {"seconds": 6}) == 2
assert ps._calculate_cost("tts", {"seconds": 5.1}) == 2
def test_video_duration_cost(self) -> None:
# video: multiplier=1,按秒向上取整
assert ps._calculate_cost("video", {"seconds": 10}) == 10
assert ps._calculate_cost("video", {"seconds": 10.2}) == 11
class TestEstimateMaxCost:
"""预估上限计算"""
def test_tts_estimate_by_char_count(self) -> None:
cfg = ps.POINTS_CONFIG["tts"]
seconds_per_char = cfg["estimation"]["seconds_per_char"]
char_count = 100
estimated_seconds = char_count * seconds_per_char
expected = max(
cfg["min_points"],
math.ceil(estimated_seconds / cfg["divisor"]),
)
result = ps._estimate_max_cost("tts", {"char_count": char_count})
assert result == expected
def test_video_estimate_by_input_seconds(self) -> None:
with pytest.raises(ValueError, match="input_seconds"):
ps._estimate_max_cost("video", {})
assert ps._estimate_max_cost("video", {"input_seconds": 10}) == 10
assert ps._estimate_max_cost("video", {"input_seconds": 10.2}) == 11
def test_unknown_source_type(self) -> None:
with pytest.raises(ValueError, match="未知的消费类型"):
ps._estimate_max_cost("not_exists")