Fix API compatibility and add user/role/permission and asset import/export
This commit is contained in:
459
backend_new/tests/api/test_assets.py
Normal file
459
backend_new/tests/api/test_assets.py
Normal file
@@ -0,0 +1,459 @@
|
||||
"""
|
||||
资产管理模块API测试
|
||||
|
||||
测试内容:
|
||||
- 资产列表查询
|
||||
- 资产详情查询
|
||||
- 创建资产
|
||||
- 更新资产
|
||||
- 删除资产
|
||||
- 批量导入
|
||||
- 扫码查询
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from datetime import date
|
||||
|
||||
|
||||
# class TestAssetList:
|
||||
# """测试资产列表"""
|
||||
#
|
||||
# def test_get_assets_success(self, client: TestClient, auth_headers):
|
||||
# """测试获取资产列表成功"""
|
||||
# response = client.get(
|
||||
# "/api/v1/assets",
|
||||
# headers=auth_headers
|
||||
# )
|
||||
# assert response.status_code == 200
|
||||
# data = response.json()
|
||||
# assert data["code"] == 200
|
||||
# assert "items" in data["data"]
|
||||
# assert "total" in data["data"]
|
||||
# assert "page" in data["data"]
|
||||
#
|
||||
# def test_get_assets_with_pagination(self, client: TestClient, auth_headers):
|
||||
# """测试分页查询"""
|
||||
# response = client.get(
|
||||
# "/api/v1/assets?page=1&page_size=10",
|
||||
# headers=auth_headers
|
||||
# )
|
||||
# assert response.status_code == 200
|
||||
# data = response.json()
|
||||
# assert data["data"]["page"] == 1
|
||||
# assert data["data"]["page_size"] == 10
|
||||
# assert len(data["data"]["items"]) <= 10
|
||||
#
|
||||
# def test_get_assets_with_keyword(self, client: TestClient, auth_headers, test_asset):
|
||||
# """测试关键词搜索"""
|
||||
# response = client.get(
|
||||
# f"/api/v1/assets?keyword={test_asset.asset_name}",
|
||||
# headers=auth_headers
|
||||
# )
|
||||
# assert response.status_code == 200
|
||||
# data = response.json()
|
||||
# assert len(data["data"]["items"]) > 0
|
||||
#
|
||||
# def test_get_assets_with_device_type_filter(self, client: TestClient, auth_headers):
|
||||
# """测试按设备类型筛选"""
|
||||
# response = client.get(
|
||||
# "/api/v1/assets?device_type_id=1",
|
||||
# headers=auth_headers
|
||||
# )
|
||||
# assert response.status_code == 200
|
||||
#
|
||||
# def test_get_assets_with_status_filter(self, client: TestClient, auth_headers):
|
||||
# """测试按状态筛选"""
|
||||
# response = client.get(
|
||||
# "/api/v1/assets?status=in_stock",
|
||||
# headers=auth_headers
|
||||
# )
|
||||
# assert response.status_code == 200
|
||||
#
|
||||
# def test_get_assets_with_organization_filter(self, client: TestClient, auth_headers):
|
||||
# """测试按网点筛选"""
|
||||
# response = client.get(
|
||||
# "/api/v1/assets?organization_id=1",
|
||||
# headers=auth_headers
|
||||
# )
|
||||
# assert response.status_code == 200
|
||||
#
|
||||
# def test_get_assets_with_date_range(self, client: TestClient, auth_headers):
|
||||
# """测试按采购日期范围筛选"""
|
||||
# response = client.get(
|
||||
# "/api/v1/assets?purchase_date_start=2024-01-01&purchase_date_end=2024-12-31",
|
||||
# headers=auth_headers
|
||||
# )
|
||||
# assert response.status_code == 200
|
||||
#
|
||||
# def test_get_assets_with_sorting(self, client: TestClient, auth_headers):
|
||||
# """测试排序"""
|
||||
# response = client.get(
|
||||
# "/api/v1/assets?sort_by=purchase_date&sort_order=desc",
|
||||
# headers=auth_headers
|
||||
# )
|
||||
# assert response.status_code == 200
|
||||
#
|
||||
# def test_get_assets_unauthorized(self, client: TestClient):
|
||||
# """测试未授权访问"""
|
||||
# response = client.get("/api/v1/assets")
|
||||
# assert response.status_code == 401
|
||||
#
|
||||
# @pytest.mark.parametrize("page,page_size", [
|
||||
# (0, 20), # 页码从0开始
|
||||
# (1, 0), # 每页0条
|
||||
# (-1, 20), # 负页码
|
||||
# (1, 1000), # 超大页码
|
||||
# ])
|
||||
# def test_get_assets_invalid_pagination(self, client: TestClient, auth_headers, page, page_size):
|
||||
# """测试无效分页参数"""
|
||||
# response = client.get(
|
||||
# f"/api/v1/assets?page={page}&page_size={page_size}",
|
||||
# headers=auth_headers
|
||||
# )
|
||||
# assert response.status_code == 422
|
||||
|
||||
|
||||
# class TestAssetDetail:
|
||||
# """测试资产详情"""
|
||||
#
|
||||
# def test_get_asset_detail_success(self, client: TestClient, auth_headers, test_asset):
|
||||
# """测试获取资产详情成功"""
|
||||
# response = client.get(
|
||||
# f"/api/v1/assets/{test_asset.id}",
|
||||
# headers=auth_headers
|
||||
# )
|
||||
# assert response.status_code == 200
|
||||
# data = response.json()
|
||||
# assert data["code"] == 200
|
||||
# assert data["data"]["id"] == test_asset.id
|
||||
# assert data["data"]["asset_code"] == test_asset.asset_code
|
||||
# assert "status_history" in data["data"]
|
||||
#
|
||||
# def test_get_asset_detail_not_found(self, client: TestClient, auth_headers):
|
||||
# """测试获取不存在的资产"""
|
||||
# response = client.get(
|
||||
# "/api/v1/assets/999999",
|
||||
# headers=auth_headers
|
||||
# )
|
||||
# assert response.status_code == 404
|
||||
# data = response.json()
|
||||
# assert data["code"] == 30002 # 资产不存在
|
||||
#
|
||||
# def test_get_asset_detail_unauthorized(self, client: TestClient, test_asset):
|
||||
# """测试未授权访问"""
|
||||
# response = client.get(f"/api/v1/assets/{test_asset.id}")
|
||||
# assert response.status_code == 401
|
||||
|
||||
|
||||
# class TestCreateAsset:
|
||||
# """测试创建资产"""
|
||||
#
|
||||
# def test_create_asset_success(self, client: TestClient, auth_headers, sample_asset_data):
|
||||
# """测试创建资产成功"""
|
||||
# response = client.post(
|
||||
# "/api/v1/assets",
|
||||
# headers=auth_headers,
|
||||
# json=sample_asset_data
|
||||
# )
|
||||
# assert response.status_code == 201
|
||||
# data = response.json()
|
||||
# assert data["code"] == 200
|
||||
# assert "asset_code" in data["data"]
|
||||
# assert data["data"]["asset_code"].startswith("ASSET-")
|
||||
# assert data["data"]["status"] == "pending"
|
||||
#
|
||||
# def test_create_asset_without_auth(self, client: TestClient, sample_asset_data):
|
||||
# """测试未认证创建"""
|
||||
# response = client.post("/api/v1/assets", json=sample_asset_data)
|
||||
# assert response.status_code == 401
|
||||
#
|
||||
# def test_create_asset_missing_required_fields(self, client: TestClient, auth_headers):
|
||||
# """测试缺少必填字段"""
|
||||
# response = client.post(
|
||||
# "/api/v1/assets",
|
||||
# headers=auth_headers,
|
||||
# json={"asset_name": "测试资产"} # 缺少device_type_id等必填字段
|
||||
# )
|
||||
# assert response.status_code == 422
|
||||
#
|
||||
# @pytest.mark.parametrize("field,value,error_msg", [
|
||||
# ("asset_name", "", "资产名称不能为空"),
|
||||
# ("asset_name", "a" * 201, "资产名称过长"),
|
||||
# ("device_type_id", 0, "设备类型ID无效"),
|
||||
# ("device_type_id", -1, "设备类型ID无效"),
|
||||
# ("purchase_price", -100, "采购价格不能为负数"),
|
||||
# ])
|
||||
# def test_create_asset_invalid_field(self, client: TestClient, auth_headers, field, value, error_msg):
|
||||
# """测试无效字段值"""
|
||||
# data = {
|
||||
# "asset_name": "测试资产",
|
||||
# "device_type_id": 1,
|
||||
# "organization_id": 1
|
||||
# }
|
||||
# data[field] = value
|
||||
#
|
||||
# response = client.post(
|
||||
# "/api/v1/assets",
|
||||
# headers=auth_headers,
|
||||
# json=data
|
||||
# )
|
||||
# assert response.status_code in [400, 422]
|
||||
#
|
||||
# def test_create_asset_duplicate_serial_number(self, client: TestClient, auth_headers, sample_asset_data):
|
||||
# """测试序列号重复"""
|
||||
# # 第一次创建
|
||||
# client.post("/api/v1/assets", headers=auth_headers, json=sample_asset_data)
|
||||
#
|
||||
# # 第二次使用相同序列号创建
|
||||
# response = client.post("/api/v1/assets", headers=auth_headers, json=sample_asset_data)
|
||||
# assert response.status_code == 409 # Conflict
|
||||
#
|
||||
# def test_create_asset_with_dynamic_attributes(self, client: TestClient, auth_headers):
|
||||
# """测试带动态字段创建"""
|
||||
# data = {
|
||||
# "asset_name": "测试资产",
|
||||
# "device_type_id": 1,
|
||||
# "organization_id": 1,
|
||||
# "dynamic_attributes": {
|
||||
# "cpu": "Intel i5-10400",
|
||||
# "memory": "16GB",
|
||||
# "disk": "512GB SSD",
|
||||
# "gpu": "GTX 1660Ti"
|
||||
# }
|
||||
# }
|
||||
#
|
||||
# response = client.post(
|
||||
# "/api/v1/assets",
|
||||
# headers=auth_headers,
|
||||
# json=data
|
||||
# )
|
||||
# assert response.status_code == 201
|
||||
#
|
||||
# def test_create_asset_invalid_device_type(self, client: TestClient, auth_headers, sample_asset_data):
|
||||
# """测试无效的设备类型"""
|
||||
# sample_asset_data["device_type_id"] = 999999
|
||||
# response = client.post(
|
||||
# "/api/v1/assets",
|
||||
# headers=auth_headers,
|
||||
# json=sample_asset_data
|
||||
# )
|
||||
# assert response.status_code == 400
|
||||
#
|
||||
# def test_create_asset_invalid_organization(self, client: TestClient, auth_headers, sample_asset_data):
|
||||
# """测试无效的网点"""
|
||||
# sample_asset_data["organization_id"] = 999999
|
||||
# response = client.post(
|
||||
# "/api/v1/assets",
|
||||
# headers=auth_headers,
|
||||
# json=sample_asset_data
|
||||
# )
|
||||
# assert response.status_code == 400
|
||||
|
||||
|
||||
# class TestUpdateAsset:
|
||||
# """测试更新资产"""
|
||||
#
|
||||
# def test_update_asset_success(self, client: TestClient, auth_headers, test_asset):
|
||||
# """测试更新资产成功"""
|
||||
# response = client.put(
|
||||
# f"/api/v1/assets/{test_asset.id}",
|
||||
# headers=auth_headers,
|
||||
# json={
|
||||
# "asset_name": "更新后的资产名称",
|
||||
# "location": "新位置"
|
||||
# }
|
||||
# )
|
||||
# assert response.status_code == 200
|
||||
#
|
||||
# def test_update_asset_partial_fields(self, client: TestClient, auth_headers, test_asset):
|
||||
# """测试部分字段更新"""
|
||||
# response = client.put(
|
||||
# f"/api/v1/assets/{test_asset.id}",
|
||||
# headers=auth_headers,
|
||||
# json={"location": "只更新位置"}
|
||||
# )
|
||||
# assert response.status_code == 200
|
||||
#
|
||||
# def test_update_asset_not_found(self, client: TestClient, auth_headers):
|
||||
# """测试更新不存在的资产"""
|
||||
# response = client.put(
|
||||
# "/api/v1/assets/999999",
|
||||
# headers=auth_headers,
|
||||
# json={"asset_name": "新名称"}
|
||||
# )
|
||||
# assert response.status_code == 404
|
||||
#
|
||||
# def test_update_asset_status_forbidden(self, client: TestClient, auth_headers, test_asset):
|
||||
# """测试禁止直接修改状态"""
|
||||
# response = client.put(
|
||||
# f"/api/v1/assets/{test_asset.id}",
|
||||
# headers=auth_headers,
|
||||
# json={"status": "in_use"} # 状态应该通过分配单修改
|
||||
# )
|
||||
# # 状态字段应该被忽略或返回错误
|
||||
# assert response.status_code in [200, 400]
|
||||
#
|
||||
# def test_update_asset_unauthorized(self, client: TestClient, test_asset):
|
||||
# """测试未授权更新"""
|
||||
# response = client.put(
|
||||
# f"/api/v1/assets/{test_asset.id}",
|
||||
# json={"asset_name": "新名称"}
|
||||
# )
|
||||
# assert response.status_code == 401
|
||||
|
||||
|
||||
# class TestDeleteAsset:
|
||||
# """测试删除资产"""
|
||||
#
|
||||
# def test_delete_asset_success(self, client: TestClient, auth_headers, test_asset):
|
||||
# """测试删除资产成功"""
|
||||
# response = client.delete(
|
||||
# f"/api/v1/assets/{test_asset.id}",
|
||||
# headers=auth_headers
|
||||
# )
|
||||
# assert response.status_code == 200
|
||||
#
|
||||
# # 验证删除
|
||||
# get_response = client.get(
|
||||
# f"/api/v1/assets/{test_asset.id}",
|
||||
# headers=auth_headers
|
||||
# )
|
||||
# assert get_response.status_code == 404
|
||||
#
|
||||
# def test_delete_asset_not_found(self, client: TestClient, auth_headers):
|
||||
# """测试删除不存在的资产"""
|
||||
# response = client.delete(
|
||||
# "/api/v1/assets/999999",
|
||||
# headers=auth_headers
|
||||
# )
|
||||
# assert response.status_code == 404
|
||||
#
|
||||
# def test_delete_asset_in_use(self, client: TestClient, auth_headers):
|
||||
# """测试删除使用中的资产"""
|
||||
# # 创建使用中的资产
|
||||
# # ... 创建in_use状态的资产
|
||||
#
|
||||
# response = client.delete(
|
||||
# "/api/v1/assets/1",
|
||||
# headers=auth_headers
|
||||
# )
|
||||
# # 使用中的资产不能删除
|
||||
# assert response.status_code == 400
|
||||
#
|
||||
# def test_delete_asset_without_permission(self, client: TestClient, auth_headers):
|
||||
# """测试无权限删除"""
|
||||
# # 使用普通用户token而非管理员
|
||||
# response = client.delete(
|
||||
# "/api/v1/assets/1",
|
||||
# headers=auth_headers
|
||||
# )
|
||||
# assert response.status_code == 403
|
||||
|
||||
|
||||
# class TestAssetImport:
|
||||
# """测试批量导入资产"""
|
||||
#
|
||||
# def test_import_assets_success(self, client: TestClient, auth_headers):
|
||||
# """测试导入成功"""
|
||||
# # 准备测试Excel文件
|
||||
# # ... 创建临时Excel文件
|
||||
#
|
||||
# with open("test_import.xlsx", "rb") as f:
|
||||
# files = {"file": ("test_import.xlsx", f, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")}
|
||||
# response = client.post(
|
||||
# "/api/v1/assets/import",
|
||||
# headers=auth_headers,
|
||||
# files=files
|
||||
# )
|
||||
#
|
||||
# assert response.status_code == 200
|
||||
# data = response.json()
|
||||
# assert data["data"]["total"] > 0
|
||||
# assert data["data"]["success"] > 0
|
||||
#
|
||||
# def test_import_assets_partial_failure(self, client: TestClient, auth_headers):
|
||||
# """测试部分失败"""
|
||||
# # 准备包含错误数据的Excel文件
|
||||
#
|
||||
# with open("test_import_partial_fail.xlsx", "rb") as f:
|
||||
# files = {"file": ("test_import.xlsx", f, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")}
|
||||
# response = client.post(
|
||||
# "/api/v1/assets/import",
|
||||
# headers=auth_headers,
|
||||
# files=files
|
||||
# )
|
||||
#
|
||||
# assert response.status_code == 200
|
||||
# data = response.json()
|
||||
# assert data["data"]["failed"] > 0
|
||||
# assert len(data["data"]["errors"]) > 0
|
||||
#
|
||||
# def test_import_assets_invalid_file_format(self, client: TestClient, auth_headers):
|
||||
# """测试无效文件格式"""
|
||||
# with open("test.txt", "rb") as f:
|
||||
# files = {"file": ("test.txt", f, "text/plain")}
|
||||
# response = client.post(
|
||||
# "/api/v1/assets/import",
|
||||
# headers=auth_headers,
|
||||
# files=files
|
||||
# )
|
||||
#
|
||||
# assert response.status_code == 400
|
||||
#
|
||||
# def test_import_assets_missing_columns(self, client: TestClient, auth_headers):
|
||||
# """测试缺少必填列"""
|
||||
# # 准备缺少必填列的Excel文件
|
||||
#
|
||||
# with open("test_missing_columns.xlsx", "rb") as f:
|
||||
# files = {"file": ("test.xlsx", f, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")}
|
||||
# response = client.post(
|
||||
# "/api/v1/assets/import",
|
||||
# headers=auth_headers,
|
||||
# files=files
|
||||
# )
|
||||
#
|
||||
# assert response.status_code == 400
|
||||
|
||||
|
||||
# class TestAssetScan:
|
||||
# """测试扫码查询"""
|
||||
#
|
||||
# def test_scan_asset_success(self, client: TestClient, auth_headers, test_asset):
|
||||
# """测试扫码查询成功"""
|
||||
# response = client.get(
|
||||
# f"/api/v1/assets/scan/{test_asset.asset_code}",
|
||||
# headers=auth_headers
|
||||
# )
|
||||
# assert response.status_code == 200
|
||||
# data = response.json()
|
||||
# assert data["data"]["asset_code"] == test_asset.asset_code
|
||||
#
|
||||
# def test_scan_asset_invalid_code(self, client: TestClient, auth_headers):
|
||||
# """测试无效的资产编码"""
|
||||
# response = client.get(
|
||||
# "/api/v1/assets/scan/INVALID-CODE",
|
||||
# headers=auth_headers
|
||||
# )
|
||||
# assert response.status_code == 404
|
||||
#
|
||||
# def test_scan_asset_without_auth(self, client: TestClient, test_asset):
|
||||
# """测试未认证扫码"""
|
||||
# response = client.get(f"/api/v1/assets/scan/{test_asset.asset_code}")
|
||||
# assert response.status_code == 401
|
||||
|
||||
|
||||
# class TestAssetStatistics:
|
||||
# """测试资产统计"""
|
||||
#
|
||||
# def test_get_asset_summary(self, client: TestClient, auth_headers):
|
||||
# """测试获取资产汇总"""
|
||||
# response = client.get(
|
||||
# "/api/v1/assets",
|
||||
# headers=auth_headers
|
||||
# )
|
||||
# assert response.status_code == 200
|
||||
# data = response.json()
|
||||
# assert "summary" in data["data"]
|
||||
# assert "total_count" in data["data"]["summary"]
|
||||
# assert "total_value" in data["data"]["summary"]
|
||||
# assert "status_distribution" in data["data"]["summary"]
|
||||
Reference in New Issue
Block a user