Files
s2f/backend/tests/test_cost_calculator.py
selfrelease 5278190750 feat: 凭证生成、成本分析、AI问答、前端页面、集成测试与E2E测试
- 后端: 凭证生成引擎、金蝶导出器、凭证模板服务
- 后端: 成本分析服务、AI问答服务
- 后端: 科目映射CRUD API、分析API、QA API
- 后端: 集成测试(认证/任务/凭证) 49个测试全部通过
- 前端: 凭证管理、成本分析、导出中心、知识库、系统设置页面
- 前端: AuthGuard认证守卫、Dashboard AI聊天功能
- 前端: Playwright E2E测试 16 passed, 1 skipped
- 基础设施: Docker Compose、Nginx反向代理、.env.example
- 文档: 用户手册、管理员手册、发布检查清单
2026-07-07 21:21:29 +08:00

150 lines
5.0 KiB
Python

"""
成本分析计算服务单元测试
测试 CostCalculatorService 和 CostSummary / DepartmentCost 的核心逻辑
"""
import pytest
from unittest.mock import AsyncMock, patch
from app.services.analysis.cost_calculator import (
CostCalculatorService,
CostSummary,
DepartmentCost,
)
@pytest.fixture
def mock_db():
"""模拟数据库会话"""
return AsyncMock()
@pytest.fixture
def cost_calculator(mock_db):
"""创建成本计算服务实例"""
return CostCalculatorService(mock_db)
class TestCostSummary:
"""成本汇总结果测试"""
def test_init_defaults(self):
"""测试默认值"""
summary = CostSummary()
assert summary.total_cost == 0.0
assert summary.salary_cost == 0.0
assert summary.social_security_cost == 0.0
assert summary.fund_cost == 0.0
assert summary.employee_count == 0
def test_init_with_values(self):
"""测试带值初始化"""
summary = CostSummary(
total_cost=50000,
salary_cost=30000,
social_security_cost=10000,
fund_cost=10000,
employee_count=10,
)
assert summary.total_cost == 50000
assert summary.salary_cost == 30000
assert summary.employee_count == 10
def test_to_dict(self):
"""测试转字典"""
summary = CostSummary(total_cost=10000, salary_cost=8000, employee_count=5)
d = summary.to_dict()
assert d["total_cost"] == 10000
assert d["salary_cost"] == 8000
assert d["employee_count"] == 5
class TestDepartmentCost:
"""部门成本测试"""
def test_init(self):
"""测试初始化"""
dept = DepartmentCost(department="技术部", employee_count=10, salary_cost=100000)
assert dept.department == "技术部"
assert dept.employee_count == 10
assert dept.salary_cost == 100000
def test_total_cost_property(self):
"""测试 total_cost 属性计算"""
dept = DepartmentCost(
department="财务部",
salary_cost=10000,
social_security_cost=3000,
fund_cost=1200,
)
assert dept.total_cost == 14200
def test_to_dict(self):
"""测试转字典"""
dept = DepartmentCost(department="技术部", salary_cost=10000, employee_count=5)
d = dept.to_dict()
assert d["department"] == "技术部"
assert d["total_cost"] == 10000
assert d["employee_count"] == 5
class TestCostCalculatorService:
"""成本计算服务测试"""
def test_init(self, mock_db):
"""测试初始化"""
service = CostCalculatorService(mock_db)
assert service.db == mock_db
@pytest.mark.asyncio
async def test_calculate_total_cost(self, cost_calculator):
"""测试计算总成本"""
mock_data = [
{"应发工资": 10000, "养老保险(公司)": 2000, "医疗保险(公司)": 1000, "失业保险(公司)": 500, "公积金(公司)": 1200},
{"应发工资": 8000, "养老保险(公司)": 1600, "医疗保险(公司)": 800, "失业保险(公司)": 400, "公积金(公司)": 960},
]
with patch.object(
cost_calculator, "_load_cleaned_data", return_value=mock_data
):
summary = await cost_calculator.calculate_total_cost(task_id=1)
assert summary.employee_count == 2
assert summary.salary_cost == 18000
assert summary.social_security_cost == 6300 # (2000+1000+500) + (1600+800+400)
assert summary.fund_cost == 2160 # 1200 + 960
assert summary.total_cost == 18000 + 6300 + 2160
@pytest.mark.asyncio
async def test_calculate_total_cost_empty(self, cost_calculator):
"""测试空数据计算"""
with patch.object(
cost_calculator, "_load_cleaned_data", return_value=[]
):
summary = await cost_calculator.calculate_total_cost(task_id=1)
assert summary.employee_count == 0
assert summary.total_cost == 0.0
@pytest.mark.asyncio
async def test_calculate_by_department(self, cost_calculator):
"""测试按部门汇总"""
mock_data = [
{"部门": "技术部", "应发工资": 10000, "养老保险(公司)": 2000, "公积金(公司)": 1200},
{"部门": "技术部", "应发工资": 8000, "养老保险(公司)": 1600, "公积金(公司)": 960},
{"部门": "财务部", "应发工资": 12000, "养老保险(公司)": 2400, "公积金(公司)": 1440},
]
with patch.object(
cost_calculator, "_load_cleaned_data", return_value=mock_data
):
departments = await cost_calculator.calculate_by_department(task_id=1)
assert len(departments) == 2
tech = [d for d in departments if d.department == "技术部"][0]
assert tech.employee_count == 2
assert tech.salary_cost == 18000
finance = [d for d in departments if d.department == "财务部"][0]
assert finance.employee_count == 1
assert finance.salary_cost == 12000