dingdanquanliucheng/backend/tests/test_system.py
2026-06-14 16:20:04 +08:00

205 lines
7.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""SYS-001 ~ SYS-016: 系统用户、角色、菜单管理测试。
覆盖功能点:
- 用户 CRUD新增、停用、重置密码
- 角色 CRUD新增、编码重复
- 菜单管理
- 角色授权
- 权限越权测试
"""
from __future__ import annotations
import pytest
@pytest.mark.system
@pytest.mark.p0
class TestUserManagement:
"""SYS-001 ~ SYS-005: 用户管理测试。"""
def test_create_user_success(self, client, admin_headers, seed_roles):
"""SYS-001: 新增用户成功。"""
resp = client.post("/api/system/users", headers=admin_headers, json={
"username": "newuser01",
"password": "password123",
"real_name": "新用户",
"mobile": "13800009001",
"role_id": 2,
})
assert resp.status_code == 200
data = resp.json()
assert data["code"] == 0
def test_duplicate_username(self, client, admin_headers, seed_users):
"""SYS-002: 用户账号重复应返回 40006。"""
resp = client.post("/api/system/users", headers=admin_headers, json={
"username": "admin01",
"password": "password123",
"real_name": "重复用户",
"role_id": 1,
})
assert resp.status_code in (400, 409)
def test_disable_user(self, client, admin_headers, seed_users, db_session):
"""SYS-004: 停用用户成功。
实际接口: POST /api/system/users/{user_id}/status
请求体: {"status": 0}
"""
from backend.app.models.system import User
user = db_session.query(User).filter(User.username == "sales01").first()
resp = client.post(f"/api/system/users/{user.id}/status", headers=admin_headers, json={
"status": 0,
})
assert resp.status_code == 200
def test_reset_password(self, client, admin_headers, seed_users, db_session):
"""SYS-005: 重置密码成功。
实际接口: POST /api/system/users/{user_id}/reset-password
请求体: {"new_password": "xxx"}
"""
from backend.app.models.system import User
user = db_session.query(User).filter(User.username == "sales01").first()
resp = client.post(f"/api/system/users/{user.id}/reset-password", headers=admin_headers, json={
"new_password": "newpassword123",
})
assert resp.status_code == 200
def test_user_list(self, client, admin_headers, seed_users):
"""SYS-015: 用户列表查询。"""
resp = client.get("/api/system/users", headers=admin_headers)
assert resp.status_code == 200
data = resp.json()
assert "list" in data["data"]
@pytest.mark.system
@pytest.mark.p0
class TestRoleManagement:
"""SYS-006 ~ SYS-008: 角色管理测试。"""
def test_create_role_success(self, client, admin_headers):
"""SYS-006: 新增角色成功。"""
resp = client.post("/api/system/roles", headers=admin_headers, json={
"role_name": "测试角色",
"role_code": "test_role",
"status": 1,
})
assert resp.status_code == 200
data = resp.json()
assert data["code"] == 0
def test_duplicate_role_code(self, client, admin_headers, seed_roles):
"""SYS-007: 角色编码重复应返回 40006。"""
resp = client.post("/api/system/roles", headers=admin_headers, json={
"role_name": "重复角色",
"role_code": "admin",
"status": 1,
})
assert resp.status_code in (400, 409)
def test_role_list(self, client, admin_headers, seed_roles):
"""角色列表查询。
注意: seed_roles fixture 创建了 5 个角色,
但 seed_data 也会创建角色(通过 seed_menus 依赖 seed_users
实际数量取决于 fixture 顺序。
"""
resp = client.get("/api/system/roles", headers=admin_headers)
assert resp.status_code == 200
data = resp.json()
# 至少有 seed_roles 创建的 5 个角色
roles = data["data"] if isinstance(data["data"], list) else data["data"].get("list", [])
assert len(roles) >= 5
@pytest.mark.system
@pytest.mark.p1
class TestMenuManagement:
"""SYS-009 ~ SYS-011: 菜单管理测试。"""
def test_create_menu_success(self, client, admin_headers):
"""SYS-009: 新增菜单成功。"""
resp = client.post("/api/system/menus", headers=admin_headers, json={
"menu_name": "测试菜单",
"menu_path": "/test",
"menu_type": "page",
"permission_code": "test:menu:view",
"sort_no": 99,
})
assert resp.status_code == 200
data = resp.json()
assert data["code"] == 0
def test_duplicate_permission_code(self, client, admin_headers, seed_menus):
"""SYS-010: 菜单权限编码重复应返回 40006。"""
resp = client.post("/api/system/menus", headers=admin_headers, json={
"menu_name": "重复菜单",
"menu_path": "/test2",
"menu_type": "page",
"permission_code": "order:list",
"sort_no": 100,
})
assert resp.status_code in (400, 409)
def test_menu_tree(self, client, admin_headers, seed_menus):
"""菜单树查询。"""
resp = client.get("/api/system/menus", headers=admin_headers)
assert resp.status_code == 200
@pytest.mark.system
@pytest.mark.p0
class TestRoleAuthorization:
"""SYS-012: 角色授权测试。"""
def test_save_role_menus(self, client, admin_headers, seed_roles, seed_menus):
"""SYS-012: 角色授权保存成功。
实际接口: PUT /api/system/roles/{role_id}/menus
"""
role_id = 2 # 业务员角色
resp = client.put(f"/api/system/roles/{role_id}/menus", headers=admin_headers, json={
"menu_ids": [1, 2, 4],
})
assert resp.status_code == 200
@pytest.mark.system
@pytest.mark.p0
class TestPermissionBoundary:
"""SYS-013: 权限越权测试。"""
def test_salesman_cannot_access_system(self, client, salesman_headers):
"""SYS-013: 业务员不能访问系统管理接口。"""
resp = client.get("/api/system/users", headers=salesman_headers)
assert resp.status_code == 403
def test_driver_cannot_access_system(self, client, driver_headers):
"""司机不能访问系统管理接口。"""
resp = client.get("/api/system/users", headers=driver_headers)
assert resp.status_code == 403
def test_manager_cannot_manage_users(self, client, manager_headers):
"""管理层不能管理用户。"""
resp = client.post("/api/system/users", headers=manager_headers, json={
"username": "test",
"password": "test",
"real_name": "test",
"role_id": 1,
})
assert resp.status_code == 403
def test_admin_full_access(self, client, admin_headers):
"""管理员可以访问所有系统管理接口。"""
resp = client.get("/api/system/users", headers=admin_headers)
assert resp.status_code == 200
resp = client.get("/api/system/roles", headers=admin_headers)
assert resp.status_code == 200
resp = client.get("/api/system/menus", headers=admin_headers)
assert resp.status_code == 200