You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
iTi-Flask/tests/test_http_utils.py

384 lines
11 KiB
Python

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

"""
HTTP 响应工具测试
"""
import pytest
from iti.applications import create_app
from iti.applications.common.utils import (
success,
fail,
page,
pagination_builder,
PaginationSchema,
)
@pytest.fixture
def app():
"""创建测试应用"""
return create_app("test")
@pytest.fixture
def client(app):
"""创建测试客户端"""
return app.test_client()
class TestSuccessFunction:
"""测试 success() 函数"""
def test_success_default(self):
"""测试默认参数"""
result = success()
assert result["code"] == 200
assert result["message"] == "成功"
assert result["data"] is None
def test_success_with_data(self):
"""测试带数据"""
data = {"id": 1, "name": "test"}
result = success(data)
assert result["code"] == 200
assert result["message"] == "成功"
assert result["data"] == data
def test_success_with_custom_message(self):
"""测试自定义消息"""
result = success({"id": 1}, message="查询成功")
assert result["code"] == 200
assert result["message"] == "查询成功"
assert result["data"]["id"] == 1
def test_success_with_custom_code(self):
"""测试自定义状态码"""
result = success({"id": 1}, message="创建成功", code=201)
assert result["code"] == 201
assert result["message"] == "创建成功"
def test_success_with_list(self):
"""测试列表数据"""
data = [{"id": 1}, {"id": 2}]
result = success(data)
assert result["code"] == 200
assert isinstance(result["data"], list)
assert len(result["data"]) == 2
class TestFailFunction:
"""测试 fail() 函数"""
def test_fail_default(self):
"""测试默认参数"""
result = fail()
assert result["code"] == 500
assert result["message"] == "操作失败"
assert result["data"] is None
def test_fail_with_custom_message(self):
"""测试自定义错误消息"""
result = fail("用户不存在")
assert result["code"] == 500
assert result["message"] == "用户不存在"
assert result["data"] is None
def test_fail_with_custom_code(self):
"""测试自定义错误码"""
result = fail("参数错误", code=400)
assert result["code"] == 400
assert result["message"] == "参数错误"
def test_fail_with_data(self):
"""测试带额外数据"""
errors = {"username": ["必填项"], "email": ["格式错误"]}
result = fail("验证失败", code=422, data=errors)
assert result["code"] == 422
assert result["message"] == "验证失败"
assert result["data"] == errors
def test_fail_returns_dict(self):
"""测试返回字典而非元组"""
result = fail("错误", code=404)
# 确保返回的是字典,不是元组
assert isinstance(result, dict)
assert "code" in result
assert "message" in result
assert "data" in result
class TestPaginationBuilder:
"""测试 pagination_builder() 函数"""
def test_manual_mode_basic(self):
"""测试手动模式基础功能"""
result = pagination_builder(None, page=1, size=10, total=100)
assert result["page"] == 1
assert result["size"] == 10
assert result["pages"] == 10 # ceil(100/10)
assert result["total"] == 100
def test_manual_mode_auto_calculate_pages(self):
"""测试自动计算总页数"""
result = pagination_builder(None, page=1, size=20, total=95)
assert result["pages"] == 5 # ceil(95/20) = 5
def test_manual_mode_with_explicit_pages(self):
"""测试显式指定总页数"""
result = pagination_builder(None, page=1, size=10, total=100, pages=8)
assert result["pages"] == 8
def test_manual_mode_zero_total(self):
"""测试总数为 0"""
result = pagination_builder(None, page=1, size=10, total=0)
assert result["pages"] == 0
assert result["total"] == 0
def test_manual_mode_urls_are_none_outside_request(self):
"""测试在请求上下文外 URL 为 None"""
result = pagination_builder(None, page=1, size=10, total=100)
assert result["current"] is None
assert result["next"] is None
assert result["prev"] is None
assert result["first"] is None
assert result["last"] is None
def test_auto_mode_with_mock_pagination(self):
"""测试自动模式(使用模拟的 Pagination 对象)"""
# 创建模拟的 Pagination 对象
class MockPagination:
page = 2
per_page = 10
pages = 10
total = 100
has_prev = True
has_next = True
prev_num = 1
next_num = 3
mock_pagination = MockPagination()
result = pagination_builder(mock_pagination)
assert result["page"] == 2
assert result["size"] == 10 # per_page → size
assert result["pages"] == 10
assert result["total"] == 100
class TestPageFunction:
"""测试 page() 函数"""
def test_page_with_list_and_dict(self):
"""测试列表 + 字典分页信息"""
items = [{"id": 1}, {"id": 2}]
pagination_info = pagination_builder(None, page=1, size=10, total=50)
result = page(items, pagination_info)
assert result["code"] == 200
assert result["message"] == "成功"
assert result["data"]["items"] == items
assert result["data"]["page"]["page"] == 1
assert result["data"]["page"]["total"] == 50
def test_page_with_custom_message(self):
"""测试自定义消息"""
items = [{"id": 1}]
pagination_info = pagination_builder(None, page=1, size=10, total=10)
result = page(items, pagination_info, message="获取列表成功")
assert result["message"] == "获取列表成功"
def test_page_with_custom_code(self):
"""测试自定义状态码"""
items = [{"id": 1}]
pagination_info = pagination_builder(None, page=1, size=10, total=10)
result = page(items, pagination_info, code=201)
assert result["code"] == 201
def test_page_with_mock_pagination_object(self):
"""测试直接传入 Pagination 对象"""
class MockPagination:
items = [{"id": 1}, {"id": 2}, {"id": 3}]
page = 1
per_page = 10
pages = 5
total = 50
has_prev = False
has_next = True
prev_num = None
next_num = 2
mock_pagination = MockPagination()
result = page(mock_pagination)
assert result["code"] == 200
assert len(result["data"]["items"]) == 3
assert result["data"]["page"]["page"] == 1
assert result["data"]["page"]["size"] == 10
assert result["data"]["page"]["total"] == 50
def test_page_with_items_and_pagination_object(self):
"""测试传入数据列表 + Pagination 对象"""
class MockPagination:
items = [{"id": 1}, {"id": 2}]
page = 2
per_page = 20
pages = 3
total = 60
has_prev = True
has_next = True
prev_num = 1
next_num = 3
mock_pagination = MockPagination()
custom_items = [{"id": 10}, {"id": 20}] # 使用自定义数据(如序列化后的)
result = page(custom_items, mock_pagination)
assert result["data"]["items"] == custom_items # 使用传入的 items
assert result["data"]["page"]["page"] == 2
assert result["data"]["page"]["size"] == 20
def test_page_empty_items(self):
"""测试空数据列表"""
items = []
pagination_info = pagination_builder(None, page=1, size=10, total=0)
result = page(items, pagination_info)
assert result["data"]["items"] == []
assert result["data"]["page"]["total"] == 0
assert result["data"]["page"]["pages"] == 0
class TestSchemaDefinitions:
"""测试 Schema 定义"""
def test_pagination_schema_exists(self):
"""测试 PaginationSchema 存在"""
assert PaginationSchema is not None
# 检查字段
schema = PaginationSchema()
assert "page" in schema.fields
assert "size" in schema.fields
assert "pages" in schema.fields
assert "total" in schema.fields
class TestIntegrationWithFlaskApp:
"""测试与 Flask 应用集成"""
def test_success_in_route(self, client):
"""测试 success() 在路由中使用"""
response = client.get("/test/success")
assert response.status_code == 200
data = response.get_json()
assert data["code"] == 200
assert data["message"] == "操作成功"
assert "message" in data["data"]
def test_fail_in_route(self, client):
"""测试 fail() 在路由中使用"""
response = client.get("/test/fail")
# 确保 HTTP 状态码是 200业务错误
assert response.status_code == 200
data = response.get_json()
assert data["code"] == 400
assert data["message"] == "这是一个错误示例"
def test_page_in_route(self, client):
"""测试 page() 在路由中使用"""
response = client.get("/test/page")
assert response.status_code == 200
data = response.get_json()
assert data["code"] == 200
assert data["message"] == "分页测试成功"
assert "items" in data["data"]
assert "page" in data["data"]
assert len(data["data"]["items"]) == 3
assert data["data"]["page"]["page"] == 1
assert data["data"]["page"]["size"] == 10
assert data["data"]["page"]["total"] == 30
def test_index_with_schema(self, client):
"""测试首页使用 Schema 验证"""
response = client.get("/")
assert response.status_code == 200
data = response.get_json()
assert data["code"] == 200
assert data["message"] == "成功"
assert "id" in data["data"]
assert "name" in data["data"]
# 验证 Schema 过滤了无关字段(如果有的话)
class TestEdgeCases:
"""测试边界情况"""
def test_pagination_builder_with_fractional_pages(self):
"""测试非整数页数计算"""
result = pagination_builder(None, page=1, size=7, total=15)
# ceil(15/7) = 3
assert result["pages"] == 3
def test_pagination_builder_exact_pages(self):
"""测试整数页数"""
result = pagination_builder(None, page=1, size=10, total=100)
assert result["pages"] == 10
def test_success_with_none_data(self):
"""测试 data 为 None"""
result = success(None, message="无数据")
assert result["data"] is None
assert result["message"] == "无数据"
def test_fail_with_empty_string_message(self):
"""测试空字符串消息"""
result = fail("", code=400)
assert result["message"] == ""
assert result["code"] == 400
def test_page_with_large_total(self):
"""测试大数据量分页"""
items = [{"id": i} for i in range(100)]
pagination_info = pagination_builder(None, page=1, size=100, total=1000000)
result = page(items, pagination_info)
assert result["data"]["page"]["total"] == 1000000
assert result["data"]["page"]["pages"] == 10000