本文目录导读:

我来详细介绍Python中数据API响应的断言编写方法:
基础断言方法
使用requests库 + 内置assert
import requests
import json
def test_api_response():
# 发送请求
response = requests.get("https://api.example.com/users/1")
# 状态码断言
assert response.status_code == 200, f"状态码错误:{response.status_code}"
# 获取JSON响应
data = response.json()
# 基本字段断言
assert "id" in data, "响应中缺少id字段"
assert "name" in data, "响应中缺少name字段"
assert "email" in data, "响应中缺少email字段"
# 值类型断言
assert isinstance(data["id"], int), "id应该是整数类型"
assert isinstance(data["name"], str), "name应该是字符串类型"
# 具体值断言
assert data["name"] == "张三", f"名称不符,期望张三,实际{data['name']}"
使用unittest框架
import unittest
import requests
import json
class TestUserAPI(unittest.TestCase):
def setUp(self):
self.base_url = "https://api.example.com"
def test_get_user(self):
response = requests.get(f"{self.base_url}/users/1")
# 状态码断言
self.assertEqual(response.status_code, 200)
data = response.json()
# 字段存在断言
self.assertIn("id", data)
self.assertIn("name", data)
# 字段值断言
self.assertEqual(data["id"], 1)
self.assertIsNotNone(data["name"])
self.assertTrue(len(data["name"]) > 0)
def test_create_user(self):
user_data = {
"name": "李四",
"email": "lisi@example.com",
"age": 25
}
response = requests.post(
f"{self.base_url}/users",
json=user_data
)
self.assertEqual(response.status_code, 201)
data = response.json()
# 验证返回的新用户数据
self.assertEqual(data["name"], user_data["name"])
self.assertEqual(data["email"], user_data["email"])
self.assertIn("id", data) # 系统应该生成ID
def test_get_nonexistent_user(self):
response = requests.get(f"{self.base_url}/users/99999")
self.assertEqual(response.status_code, 404)
data = response.json()
self.assertIn("error", data)
self.assertEqual(data["error"], "用户不存在")
if __name__ == "__main__":
unittest.main()
使用pytest框架(推荐)
import pytest
import requests
import json
# fixture提供测试数据
@pytest.fixture
def api_client():
return "https://api.example.com"
@pytest.fixture
def sample_user_data():
return {
"name": "王五",
"email": "wangwu@example.com",
"age": 30
}
def test_get_user_success(api_client):
"""测试获取用户成功"""
response = requests.get(f"{api_client}/users/1")
# 状态码断言
assert response.status_code == 200
data = response.json()
# 综合断言
assert all(key in data for key in ["id", "name", "email", "age"])
assert isinstance(data["id"], int)
assert isinstance(data["name"], str)
assert data["id"] == 1
def test_create_user(api_client, sample_user_data):
"""测试创建用户"""
response = requests.post(
f"{api_client}/users",
json=sample_user_data
)
assert response.status_code == 201
assert response.headers["Content-Type"] == "application/json"
created_user = response.json()
assert created_user["name"] == sample_user_data["name"]
assert created_user["email"] == sample_user_data["email"]
assert "id" in created_user
def test_update_user(api_client):
"""测试更新用户"""
update_data = {"name": "赵六", "age": 35}
response = requests.put(
f"{api_client}/users/1",
json=update_data
)
assert response.status_code == 200
updated_user = response.json()
assert updated_user["name"] == update_data["name"]
assert updated_user["age"] == update_data["age"]
def test_delete_user(api_client):
"""测试删除用户"""
response = requests.delete(f"{api_client}/users/1")
assert response.status_code == 204
# 204无内容响应,不应该有body
assert len(response.content) == 0
@pytest.mark.parametrize("user_id,expected_status", [
(1, 200),
(-1, 400),
(99999, 404),
])
def test_get_user_parameterized(api_client, user_id, expected_status):
"""参数化测试不同用户ID"""
response = requests.get(f"{api_client}/users/{user_id}")
assert response.status_code == expected_status
高级断言技巧
import requests
from datetime import datetime
def advanced_assertions():
response = requests.get("https://api.example.com/users/1")
data = response.json()
# 1. 正则表达式匹配
import re
assert re.match(r"^\w+@\w+\.\w+$", data["email"]), "邮箱格式不正确"
# 2. 数值范围断言
assert 0 <= data["age"] <= 150, f"年龄超出范围:{data['age']}"
# 3. 日期格式断言
try:
datetime.fromisoformat(data["created_at"])
except ValueError:
assert False, "日期格式不正确"
# 4. 列表断言
assert len(data.get("tags", [])) > 0, "用户至少需要一个标签"
assert all(isinstance(tag, str) for tag in data["tags"]), "标签应为字符串"
# 5. 嵌套JSON断言
address = data.get("address", {})
assert "city" in address and "province" in address
# 6. 响应时间断言
assert response.elapsed.total_seconds() < 5, "响应过慢"
# 7. 响应头断言
assert response.headers["Content-Type"] == "application/json"
# 使用第三方库:jsonschema进行JSON Schema验证
from jsonschema import validate, ValidationError
def test_with_json_schema():
schema = {
"type": "object",
"required": ["id", "name", "email"],
"properties": {
"id": {"type": "integer", "minimum": 1},
"name": {"type": "string", "minLength": 1},
"email": {"type": "string", "format": "email"},
"age": {"type": "integer", "minimum": 0, "maximum": 150},
"address": {
"type": "object",
"properties": {
"city": {"type": "string"},
"province": {"type": "string"}
}
}
}
}
response = requests.get("https://api.example.com/users/1")
data = response.json()
try:
validate(instance=data, schema=schema)
assert True
except ValidationError as e:
assert False, f"JSON Schema验证失败:{e.message}"
实际项目中的断言工具类
class APIResponseAssertions:
@staticmethod
def assert_status_code(response, expected_code=200):
assert response.status_code == expected_code, \
f"期望状态码{expected_code},实际{response.status_code}"
@staticmethod
def assert_required_fields(data, required_fields):
missing_fields = [field for field in required_fields if field not in data]
assert not missing_fields, f"缺少必要字段:{missing_fields}"
@staticmethod
def assert_field_types(data, type_map):
for field, expected_type in type_map.items():
assert field in data, f"缺少字段:{field}"
assert isinstance(data[field], expected_type), \
f"字段{field}类型错误,期望{expected_type},实际{type(data[field])}"
@staticmethod
def assert_response_time(response, max_seconds=3):
assert response.elapsed.total_seconds() < max_seconds, \
f"响应过慢:{response.elapsed.total_seconds()}秒"
@staticmethod
def assert_pagination(response, expected_page=None, expected_per_page=None):
data = response.json()
assert "page" in data
assert "per_page" in data
assert "total" in data
assert "total_pages" in data
if expected_page:
assert data["page"] == expected_page
if expected_per_page:
assert data["per_page"] == expected_per_page
# 使用示例
def test_complex_api():
assertions = APIResponseAssertions()
response = requests.get("https://api.example.com/users?page=1&per_page=10")
assertions.assert_status_code(response, 200)
assertions.assert_response_time(response, 5)
assertions.assert_pagination(response, expected_page=1, expected_per_page=10)
data = response.json()
assertions.assert_required_fields(data, ["users", "page", "per_page", "total"])
for user in data["users"]:
assertions.assert_required_fields(user, ["id", "name", "email"])
assertions.assert_field_types(user, {
"id": int,
"name": str,
"email": str
})
- 分离测试数据和断言逻辑
- 使用fixture管理测试准备和清理
- 参数化测试覆盖不同场景
- 分组测试用例,便于管理和报告
- 添加清晰的断言错误信息
- 合理使用超时和重试机制
- 测试数据和代码进行版本控制
这些方法可以根据具体项目需求进行调整和组合使用。