签入版本
This commit is contained in:
@@ -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] == ["产品经理", "项目经理"]
|
||||
Reference in New Issue
Block a user