签入版本

This commit is contained in:
2026-09-12 19:09:28 +08:00
commit 4eae62bc17
803 changed files with 105034 additions and 0 deletions
@@ -0,0 +1,114 @@
"""
岗位服务单元测试(P4 服务层改造标杆)
=============================================================
验证 P4 改造后的服务层契约:
- 服务函数「入参数据、出参数据」
- 业务失败通过 raise BizError 表达(不再 return R.failed)
- 纯函数与可 mock 路径无需数据库即可测试
"""
import pytest
from src.common.utils.model_utils import build_page_data
from src.core.exceptions import BizError
from src.modules.system.position import service as position_service
class TestBuildPageData:
"""分页数据构建(纯函数)"""
def test_shape(self):
data = build_page_data([], 0, 1, 10)
assert data == {'records': [], 'total': 0, 'size': 10, 'current': 1, 'pages': 0}
class TestAddPosition:
"""添加岗位"""
def test_empty_data_raises_bizerror(self, flask_app):
"""空数据触发表单验证失败 → BizError(FlaskForm 需应用上下文)"""
with flask_app.app_context():
with pytest.raises(BizError):
position_service.add_position({})
class TestUpdatePosition:
"""更新岗位"""
def test_empty_data_raises_bizerror(self, flask_app):
with flask_app.app_context():
with pytest.raises(BizError):
position_service.update_position({})
class TestUpdateStatus:
"""状态设置"""
def test_empty_data_raises_bizerror(self, flask_app):
with flask_app.app_context():
with pytest.raises(BizError):
position_service.update_position_status({})
class TestDeletePositions:
"""批量删除"""
def test_empty_raises(self):
"""空 ID 触发 BizError"""
with pytest.raises(BizError, match="记录ID不存在"):
position_service.delete_positions('')
def test_invalid_ids_raises(self):
"""非数字 ID 解析为空 → BizError"""
with pytest.raises(BizError, match="无效的记录ID"):
position_service.delete_positions('abc')
def test_parse_and_delete(self, app, monkeypatch):
"""ID 解析后调用仓库批量删除,返回删除计数(before_delete 引用校验需 DB 上下文)"""
from src.modules.system.position.repository import PositionRepository
captured = {}
def fake_batch_delete(cls, ids):
captured['ids'] = ids
return len(ids)
monkeypatch.setattr(PositionRepository, 'batch_delete', classmethod(fake_batch_delete))
with app.app_context():
count = position_service.delete_positions('1,2,3')
assert count == 3
assert captured['ids'] == [1, 2, 3]
class TestPositionList:
"""岗位列表(无分页):参数条件筛选 + status=1 硬性过滤"""
@pytest.fixture
def seed_positions(self, app):
from src.core.database import db
from src.modules.system.position.repository import PositionRepository
with app.app_context():
PositionRepository.create(name="产品经理", status=1, sort=1)
PositionRepository.create(name="项目经理", status=1, sort=2)
PositionRepository.create(name="测试主管", status=0, sort=3)
db.session.commit()
def test_list_no_filter_returns_enabled_only(self, app, seed_positions):
with app.app_context():
data = position_service.get_position_list(None)
assert [d["name"] for d in data] == ["产品经理", "项目经理"]
def test_list_filters_by_name(self, app, seed_positions):
with app.app_context():
data = position_service.get_position_list({"name": "经理"})
assert [d["name"] for d in data] == ["产品经理", "项目经理"]
def test_list_status_param_is_ignored(self, app, seed_positions):
# status 为硬性条件,即使传入 status=0 也只返回启用(status=1)记录
with app.app_context():
data = position_service.get_position_list({"name": "经理", "status": 0})
assert [d["name"] for d in data] == ["产品经理", "项目经理"]