本文目录导读:
我来通过几个具体案例来说明如何使用Python测试API接口,我会从简单到复杂逐步展示。
准备工作:安装必要的库
pip install requests pytest pydantic
基础测试案例
1 测试GET请求
# test_get_api.py
import requests
import json
def test_get_users():
"""测试获取用户列表接口"""
url = "https://jsonplaceholder.typicode.com/users"
# 发送GET请求
response = requests.get(url)
# 验证状态码
assert response.status_code == 200, f"期望200,实际{response.status_code}"
# 验证响应体
users = response.json()
assert isinstance(users, list), "响应应该是列表"
assert len(users) > 0, "用户列表不应为空"
# 验证用户数据结构
first_user = users[0]
assert "id" in first_user, "用户应该有id字段"
assert "name" in first_user, "用户应该有name字段"
assert "email" in first_user, "用户应该有email字段"
print(f"测试通过!获取到{len(users)}个用户")
print(f"第一个用户: {first_user['name']}")
def test_get_user_by_id():
"""测试获取单个用户"""
url = "https://jsonplaceholder.typicode.com/users/1"
response = requests.get(url)
assert response.status_code == 200
user = response.json()
assert user["id"] == 1
assert user["name"] == "Leanne Graham"
print(f"用户信息: {user['name']} - {user['email']}")
# 运行测试
if __name__ == "__main__":
test_get_users()
test_get_user_by_id()
2 测试POST请求
# test_post_api.py
import requests
import json
class TestCreateAPI:
"""测试创建资源的API"""
def test_create_post(self):
"""测试创建新文章"""
url = "https://jsonplaceholder.typicode.com/posts"
# 准备请求数据
post_data = {
"title": "Python API测试",
"body": "这是通过Python测试创建的文章内容",
"userId": 1
}
# 发送POST请求
response = requests.post(
url,
json=post_data,
headers={"Content-Type": "application/json"}
)
# 验证响应
assert response.status_code == 201, f"期望201 Created,实际{response.status_code}"
# 验证响应数据
created_post = response.json()
assert created_post["title"] == post_data["title"]
assert created_post["body"] == post_data["body"]
assert "id" in created_post, "创建成功应返回id"
print(f"文章创建成功!ID: {created_post['id']}")
print(f"文章标题: {created_post['title']}")
def test_create_with_validation(self):
"""测试请求验证"""
url = "https://jsonplaceholder.typicode.com/posts"
# 测试缺少必填字段
invalid_data = {"title": "缺少body"} # 缺少body和userId
response = requests.post(url, json=invalid_data)
# 注意:jsonplaceholder不会验证,这里只是演示
print(f"响应状态码: {response.status_code}")
# 运行测试
if __name__ == "__main__":
test = TestCreateAPI()
test.test_create_post()
3 使用pytest框架进行测试
# test_api_with_pytest.py
import requests
import pytest
class TestUserAPI:
"""使用pytest框架测试用户API"""
BASE_URL = "https://jsonplaceholder.typicode.com"
@pytest.fixture
def api_client(self):
"""创建API客户端"""
session = requests.Session()
session.headers.update({"Content-Type": "application/json"})
yield session
session.close()
def test_get_all_users(self, api_client):
"""测试获取所有用户"""
response = api_client.get(f"{self.BASE_URL}/users")
assert response.status_code == 200
users = response.json()
assert len(users) >= 10 # jsonplaceholder有10个用户
# 验证每个用户都有必要字段
required_fields = ["id", "name", "email", "address"]
for user in users:
for field in required_fields:
assert field in user, f"用户缺少{field}字段"
@pytest.mark.parametrize("user_id, expected_name", [
(1, "Leanne Graham"),
(2, "Ervin Howell"),
(3, "Clementine Bauch")
])
def test_get_specific_user(self, api_client, user_id, expected_name):
"""参数化测试多个用户"""
response = api_client.get(f"{self.BASE_URL}/users/{user_id}")
assert response.status_code == 200
user = response.json()
assert user["name"] == expected_name
def test_user_not_found(self, api_client):
"""测试用户不存在的情况"""
response = api_client.get(f"{self.BASE_URL}/users/999")
assert response.status_code == 404
# 在命令行运行:pytest test_api_with_pytest.py -v
高级测试案例
1 使用数据验证
# test_with_validation.py
import requests
from pydantic import BaseModel, Field, validator
from typing import List
class Geo(BaseModel):
"""地理坐标模型"""
lat: str
lng: str
class Address(BaseModel):
"""地址模型"""
street: str
suite: str
city: str
zipcode: str
geo: Geo
class Company(BaseModel):
"""公司信息模型"""
name: str
catchPhrase: str
bs: str
class User(BaseModel):
"""用户模型"""
id: int
name: str
username: str
email: str
address: Address
phone: str
website: str
company: Company
@validator('email')
def validate_email(cls, v):
assert '@' in v, f"无效的邮箱: {v}"
return v
def test_user_with_pydantic():
"""使用Pydantic验证响应数据"""
url = "https://jsonplaceholder.typicode.com/users/1"
response = requests.get(url)
# 使用Pydantic模型验证
user = User(**response.json())
print(f"用户验证通过: {user.name}")
print(f"邮箱: {user.email}")
print(f"城市: {user.address.city}")
if __name__ == "__main__":
test_user_with_pydantic()
2 完整的测试套件
# complete_api_test_suite.py
import requests
import json
import time
from datetime import datetime
class APITestSuite:
"""完整的API测试套件"""
def __init__(self, base_url):
self.base_url = base_url
self.session = requests.Session()
self.results = []
def test_get_request(self, endpoint, expected_status=200):
"""测试GET请求"""
url = f"{self.base_url}{endpoint}"
start_time = time.time()
try:
response = self.session.get(url)
response_time = time.time() - start_time
result = {
"endpoint": endpoint,
"method": "GET",
"status_code": response.status_code,
"response_time": f"{response_time:.2f}s",
"passed": response.status_code == expected_status
}
if result["passed"]:
result["message"] = f"GET {endpoint} 成功"
else:
result["message"] = f"期望{expected_status},实际{response.status_code}"
self.results.append(result)
return result
except Exception as e:
self.results.append({
"endpoint": endpoint,
"method": "GET",
"status_code": None,
"response_time": f"{time.time() - start_time:.2f}s",
"passed": False,
"message": f"请求失败: {str(e)}"
})
def test_post_request(self, endpoint, data, expected_status=201):
"""测试POST请求"""
url = f"{self.base_url}{endpoint}"
start_time = time.time()
try:
response = self.session.post(url, json=data)
response_time = time.time() - start_time
result = {
"endpoint": endpoint,
"method": "POST",
"status_code": response.status_code,
"response_time": f"{response_time:.2f}s",
"passed": response.status_code == expected_status
}
if result["passed"]:
result["message"] = f"POST {endpoint} 成功"
else:
result["message"] = f"期望{expected_status},实际{response.status_code}"
self.results.append(result)
return result
except Exception as e:
self.results.append({
"endpoint": endpoint,
"method": "POST",
"status_code": None,
"response_time": f"{time.time() - start_time:.2f}s",
"passed": False,
"message": f"请求失败: {str(e)}"
})
def generate_report(self):
"""生成测试报告"""
print("\n" + "="*50)
print("API测试报告")
print(f"测试时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print("="*50)
passed = sum(1 for r in self.results if r["passed"])
failed = len(self.results) - passed
print(f"总用例: {len(self.results)}")
print(f"通过: {passed}")
print(f"失败: {failed}")
print("-"*50)
for result in self.results:
status = "✅" if result["passed"] else "❌"
print(f"{status} {result['method']} {result['endpoint']}")
print(f" 状态码: {result['status_code']}")
print(f" 响应时间: {result['response_time']}")
print(f" 消息: {result['message']}")
print()
return passed == len(self.results)
# 运行测试套件
if __name__ == "__main__":
# 创建测试套件
test_suite = APITestSuite("https://jsonplaceholder.typicode.com")
# 运行测试
test_suite.test_get_request("/users")
test_suite.test_get_request("/users/1")
test_suite.test_get_request("/users/999", expected_status=404)
test_suite.test_get_request("/posts/1/comments")
# POST测试
new_post = {
"title": "测试文章",
"body": "这是一篇测试文章",
"userId": 1
}
test_suite.test_post_request("/posts", new_post)
# 生成报告
test_suite.generate_report()
测试的最佳实践
1 测试配置文件
# config.py
class TestConfig:
"""测试配置"""
BASE_URL = "https://jsonplaceholder.typicode.com"
TIMEOUT = 30 # 超时时间
RETRY_COUNT = 3 # 重试次数
# API端点
ENDPOINTS = {
"users": "/users",
"posts": "/posts",
"comments": "/comments"
}
2 使用requests-mock进行模拟测试
# test_with_mock.py
import requests
import pytest
from unittest.mock import Mock, patch
def test_api_with_mock():
"""使用mock测试API"""
# 模拟API响应
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {
"id": 1,
"name": "测试用户",
"email": "test@example.com"
}
# 模拟requests.get
with patch('requests.get', return_value=mock_response):
response = requests.get("https://api.example.com/user/1")
assert response.status_code == 200
data = response.json()
assert data["name"] == "测试用户"
print("模拟测试通过!")
if __name__ == "__main__":
test_api_with_mock()
运行测试
# 运行单个测试文件 python test_get_api.py # 使用pytest运行所有测试 pytest test_api_with_pytest.py -v # 生成详细报告 pytest test_api_with_pytest.py -v --tb=long # 运行特定测试 pytest test_api_with_pytest.py::TestUserAPI::test_get_all_users -v
这些案例涵盖了从基础到高级的API测试方法,你可以根据实际需求选择合适的测试方式,建议从简单的方案开始,逐步增加测试的复杂度和覆盖率。
标签: Python