Files
smart-project-pricing/后端服务/tests/test_services/test_profit_service.py
2026-01-31 21:33:06 +08:00

212 lines
6.0 KiB
Python

"""利润模拟服务单元测试
测试 ProfitService 的核心业务逻辑
"""
import pytest
from decimal import Decimal
from unittest.mock import AsyncMock, patch, MagicMock
from sqlalchemy.ext.asyncio import AsyncSession
from app.services.profit_service import ProfitService
from app.schemas.profit import PeriodType
from app.models import PricingPlan, FixedCost
class TestProfitService:
"""利润模拟服务测试类"""
@pytest.mark.unit
def test_calculate_profit_basic(self):
"""测试基础利润计算"""
service = ProfitService(None)
revenue, cost, profit, margin = service.calculate_profit(
price=100.0,
cost_per_unit=60.0,
volume=100
)
assert revenue == 10000.0
assert cost == 6000.0
assert profit == 4000.0
assert margin == 40.0
@pytest.mark.unit
def test_calculate_profit_zero_revenue(self):
"""测试零收入时的处理"""
service = ProfitService(None)
revenue, cost, profit, margin = service.calculate_profit(
price=100.0,
cost_per_unit=60.0,
volume=0
)
assert revenue == 0
assert cost == 0
assert profit == 0
assert margin == 0
@pytest.mark.unit
def test_calculate_profit_negative(self):
"""测试亏损情况"""
service = ProfitService(None)
revenue, cost, profit, margin = service.calculate_profit(
price=50.0,
cost_per_unit=60.0,
volume=100
)
assert revenue == 5000.0
assert cost == 6000.0
assert profit == -1000.0
assert margin == -20.0
@pytest.mark.unit
def test_calculate_breakeven_basic(self):
"""测试基础盈亏平衡计算"""
service = ProfitService(None)
breakeven = service.calculate_breakeven(
price=100.0,
variable_cost=60.0,
fixed_cost=0
)
assert breakeven == 1
@pytest.mark.unit
def test_calculate_breakeven_with_fixed_cost(self):
"""测试有固定成本的盈亏平衡"""
service = ProfitService(None)
breakeven = service.calculate_breakeven(
price=100.0,
variable_cost=60.0,
fixed_cost=4000.0
)
assert breakeven == 101
@pytest.mark.unit
def test_calculate_breakeven_no_margin(self):
"""测试边际贡献为负时的处理"""
service = ProfitService(None)
breakeven = service.calculate_breakeven(
price=50.0,
variable_cost=60.0,
fixed_cost=1000.0
)
assert breakeven == 999999
@pytest.mark.unit
@pytest.mark.asyncio
async def test_get_pricing_plan(
self,
db_session: AsyncSession,
sample_pricing_plan: PricingPlan
):
"""测试获取定价方案"""
service = ProfitService(db_session)
plan = await service.get_pricing_plan(sample_pricing_plan.id)
assert plan.id == sample_pricing_plan.id
assert plan.plan_name == "2026年Q1定价"
@pytest.mark.unit
@pytest.mark.asyncio
async def test_get_pricing_plan_not_found(
self,
db_session: AsyncSession
):
"""测试获取不存在的方案"""
service = ProfitService(db_session)
with pytest.raises(ValueError, match="定价方案不存在"):
await service.get_pricing_plan(99999)
@pytest.mark.unit
@pytest.mark.asyncio
async def test_get_monthly_fixed_cost(
self,
db_session: AsyncSession,
sample_fixed_cost: FixedCost
):
"""测试获取月度固定成本"""
service = ProfitService(db_session)
total = await service.get_monthly_fixed_cost()
assert total == Decimal("30000.00")
@pytest.mark.unit
@pytest.mark.asyncio
async def test_simulate_profit(
self,
db_session: AsyncSession,
sample_pricing_plan: PricingPlan
):
"""测试利润模拟"""
service = ProfitService(db_session)
response = await service.simulate_profit(
pricing_plan_id=sample_pricing_plan.id,
price=580.0,
estimated_volume=100,
period_type=PeriodType.MONTHLY,
)
assert response.pricing_plan_id == sample_pricing_plan.id
assert response.input.price == 580.0
assert response.input.estimated_volume == 100
@pytest.mark.unit
@pytest.mark.asyncio
async def test_sensitivity_analysis(
self,
db_session: AsyncSession,
sample_pricing_plan: PricingPlan
):
"""测试敏感性分析"""
service = ProfitService(db_session)
sim_response = await service.simulate_profit(
pricing_plan_id=sample_pricing_plan.id,
price=580.0,
estimated_volume=100,
period_type=PeriodType.MONTHLY,
)
response = await service.sensitivity_analysis(
simulation_id=sim_response.simulation_id,
price_change_rates=[-20, -10, 0, 10, 20]
)
assert response.simulation_id == sim_response.simulation_id
assert len(response.sensitivity_results) == 5
@pytest.mark.unit
@pytest.mark.asyncio
async def test_breakeven_analysis(
self,
db_session: AsyncSession,
sample_pricing_plan: PricingPlan,
sample_fixed_cost: FixedCost
):
"""测试盈亏平衡分析"""
service = ProfitService(db_session)
response = await service.breakeven_analysis(
pricing_plan_id=sample_pricing_plan.id
)
assert response.pricing_plan_id == sample_pricing_plan.id
assert response.price > 0
assert response.breakeven_volume > 0