1. 项目概述
Requests模块是Python中最流行的HTTP客户端库,在API接口自动化测试领域占据着不可替代的地位。作为一个从业多年的测试工程师,我见证了Requests从最初的0.x版本发展到如今的2.x版本,它几乎成为了Python开发者与Web服务交互的事实标准。
在实际测试工作中,Requests模块之所以如此受欢迎,主要源于以下几个核心优势:
- 简洁直观的API设计:相比Python内置的urllib库,Requests的API更加人性化,开发者可以更专注于业务逻辑而非底层细节
- 完善的HTTP协议支持:从基础的GET/POST到复杂的认证、会话管理、文件上传等场景都能优雅处理
- 丰富的扩展生态:配合pytest、unittest等测试框架可以快速构建完整的自动化测试方案
提示:虽然Python标准库中有urllib/urllib2等HTTP客户端,但在实际测试项目中,99%的团队都会选择Requests作为基础工具,这是经过行业验证的最佳实践。
2. 环境准备与安装
2.1 Python环境配置
在开始使用Requests之前,需要确保具备可用的Python环境。我推荐使用Python 3.6+版本,这是目前大多数企业测试环境的标配。可以通过以下命令检查Python版本:
bash复制python --version
# 或
python3 --version
对于测试工程师而言,建议使用虚拟环境来隔离项目依赖。以下是创建和使用虚拟环境的标准流程:
bash复制# 创建虚拟环境
python -m venv api_test_env
# 激活环境(Windows)
api_test_env\Scripts\activate.bat
# 激活环境(Mac/Linux)
source api_test_env/bin/activate
2.2 Requests模块安装
在激活的虚拟环境中,使用pip安装Requests模块:
bash复制pip install requests
安装完成后,可以通过以下方式验证安装是否成功:
python复制import requests
print(requests.__version__) # 应输出类似2.25.1的版本号
注意:在企业测试环境中,可能会遇到网络代理限制。此时可以通过以下方式指定代理安装:
bash复制pip install --proxy=http://proxy.example.com:8080 requests
3. Requests核心功能详解
3.1 基础HTTP请求方法
3.1.1 GET请求
GET是最常用的HTTP方法,用于获取资源。以下是带参数的标准GET请求示例:
python复制import requests
# 基础GET请求
response = requests.get('https://api.example.com/users')
# 带查询参数的GET请求
params = {'page': 1, 'limit': 20}
response = requests.get('https://api.example.com/users', params=params)
# 获取响应内容
print(response.status_code) # HTTP状态码
print(response.json()) # 解析JSON响应体
print(response.headers) # 响应头信息
在实际测试中,我通常会添加超时控制,避免测试用例长时间阻塞:
python复制response = requests.get('https://api.example.com/users', timeout=5) # 5秒超时
3.1.2 POST请求
POST方法常用于创建资源或提交数据。以下是几种常见的POST请求形式:
python复制# 表单形式POST
data = {'username': 'test', 'password': '123456'}
response = requests.post('https://api.example.com/login', data=data)
# JSON形式POST
import json
headers = {'Content-Type': 'application/json'}
data = {'title': '测试文章', 'content': '这是正文内容'}
response = requests.post(
'https://api.example.com/articles',
data=json.dumps(data),
headers=headers
)
# 更简洁的JSON POST写法(推荐)
response = requests.post(
'https://api.example.com/articles',
json=data, # 使用json参数会自动序列化并设置Content-Type
headers=headers
)
3.2 高级功能应用
3.2.1 会话管理
对于需要保持会话的测试场景(如登录态维持),可以使用Session对象:
python复制# 创建会话
session = requests.Session()
# 登录操作
login_data = {'username': 'test', 'password': '123456'}
session.post('https://api.example.com/login', data=login_data)
# 后续请求自动携带cookies
profile = session.get('https://api.example.com/profile')
orders = session.get('https://api.example.com/orders')
实操心得:在测试RESTful API时,Session对象可以大幅简化认证流程。我曾在一个电商项目测试中,通过Session将测试用例执行时间缩短了40%。
3.2.2 文件上传
测试文件上传接口时,可以使用files参数:
python复制# 单文件上传
with open('test.jpg', 'rb') as f:
files = {'file': ('test.jpg', f, 'image/jpeg')}
response = requests.post('https://api.example.com/upload', files=files)
# 多文件上传
files = [
('images', ('test1.jpg', open('test1.jpg', 'rb'), 'image/jpeg')),
('images', ('test2.png', open('test2.png', 'rb'), 'image/png'))
]
response = requests.post('https://api.example.com/multi-upload', files=files)
3.2.3 超时与重试
在实际测试环境中,网络不稳定是常见问题。可以通过以下方式增强测试稳定性:
python复制from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
# 创建带重试机制的Session
session = requests.Session()
retries = Retry(
total=3, # 总重试次数
backoff_factor=1, # 重试间隔增长因子
status_forcelist=[500, 502, 503, 504] # 需要重试的状态码
)
session.mount('https://', HTTPAdapter(max_retries=retries))
# 使用增强的Session发送请求
try:
response = session.get('https://api.example.com/unstable-api', timeout=5)
except requests.exceptions.RequestException as e:
print(f"请求最终失败: {e}")
4. 测试框架集成实践
4.1 与unittest集成
将Requests封装成可重用的测试基类:
python复制import unittest
import requests
class APITestCase(unittest.TestCase):
BASE_URL = 'https://api.example.com'
def setUp(self):
self.session = requests.Session()
# 初始化测试数据等操作
def tearDown(self):
self.session.close()
# 清理测试数据等操作
def test_user_creation(self):
"""测试用户创建接口"""
url = f"{self.BASE_URL}/users"
data = {'name': 'testuser', 'email': 'test@example.com'}
response = self.session.post(url, json=data)
self.assertEqual(response.status_code, 201)
self.assertIn('id', response.json())
# 更多测试用例...
4.2 与pytest集成
利用pytest的fixture机制创建更灵活的测试结构:
python复制import pytest
import requests
@pytest.fixture(scope="module")
def api_client():
"""创建测试用的API客户端"""
client = requests.Session()
client.base_url = "https://api.example.com"
yield client
client.close()
def test_get_user(api_client):
"""测试获取用户信息接口"""
response = api_client.get(f"{api_client.base_url}/users/1")
assert response.status_code == 200
assert response.json()['id'] == 1
@pytest.mark.parametrize("user_id,expected_status", [
(1, 200),
(999, 404),
("invalid", 400)
])
def test_get_user_with_params(api_client, user_id, expected_status):
"""参数化测试不同用户ID的情况"""
response = api_client.get(f"{api_client.base_url}/users/{user_id}")
assert response.status_code == expected_status
5. 常见问题与调试技巧
5.1 请求失败排查
当请求失败时,可以按照以下步骤排查:
- 检查网络连接:
python复制import socket
try:
socket.create_connection(("api.example.com", 443), timeout=5)
print("网络连接正常")
except socket.error as e:
print(f"网络连接失败: {e}")
- 启用详细日志记录:
python复制import logging
import http.client
# 启用Requests和HTTP连接日志
logging.basicConfig(level=logging.DEBUG)
http.client.HTTPConnection.debuglevel = 1
- 检查请求详情:
python复制# 打印请求准备信息
request = requests.Request('GET', 'https://api.example.com/users')
prepared = request.prepare()
print(f"Method: {prepared.method}")
print(f"URL: {prepared.url}")
print("Headers:")
for k, v in prepared.headers.items():
print(f" {k}: {v}")
print(f"Body: {prepared.body}")
5.2 性能优化建议
在大量API测试场景中,Requests的性能优化尤为重要:
- 连接池复用:
python复制# 默认情况下Session已经启用了连接池
session = requests.Session()
for i in range(10):
session.get('https://api.example.com/users') # 复用TCP连接
- 禁用SSL验证(仅测试环境):
python复制# 在测试环境中可以临时关闭SSL验证加速测试
response = requests.get('https://api.example.com/users', verify=False)
- 启用HTTP/2(需要安装hyper包):
bash复制pip install hyper
python复制session = requests.Session()
session.mount('https://', HTTPAdapter(pool_connections=10, pool_maxsize=100, max_retries=3))
5.3 安全性注意事项
在测试过程中需要注意以下安全实践:
- 敏感信息处理:
python复制# 使用环境变量存储凭证
import os
from dotenv import load_dotenv
load_dotenv() # 加载.env文件
api_key = os.getenv('API_KEY')
response = requests.get(
'https://api.example.com/sensitive',
headers={'Authorization': f'Bearer {api_key}'}
)
- 请求签名验证:
python复制import hmac
import hashlib
import time
def generate_signature(secret, data):
timestamp = str(int(time.time()))
message = timestamp + data
signature = hmac.new(
secret.encode('utf-8'),
message.encode('utf-8'),
hashlib.sha256
).hexdigest()
return timestamp, signature
secret = 'your_shared_secret'
data = 'test_data'
timestamp, signature = generate_signature(secret, data)
headers = {
'X-Auth-Timestamp': timestamp,
'X-Auth-Signature': signature
}
response = requests.post('https://api.example.com/secured', headers=headers)
6. 实际测试案例解析
6.1 电商API测试实战
假设我们需要测试一个电商平台的商品API,以下是完整的测试流程:
python复制import pytest
import requests
class TestECommerceAPI:
BASE_URL = "https://api.ecommerce.example.com"
@pytest.fixture
def auth_token(self):
"""获取认证token"""
login_url = f"{self.BASE_URL}/auth/login"
creds = {"username": "testuser", "password": "Test@123"}
response = requests.post(login_url, json=creds)
assert response.status_code == 200
return response.json()["token"]
@pytest.fixture
def auth_client(self, auth_token):
"""创建认证客户端"""
client = requests.Session()
client.headers.update({
"Authorization": f"Bearer {auth_token}",
"Content-Type": "application/json"
})
yield client
client.close()
def test_product_listing(self, auth_client):
"""测试商品列表接口"""
url = f"{self.BASE_URL}/products"
params = {"page": 1, "category": "electronics"}
response = auth_client.get(url, params=params)
assert response.status_code == 200
data = response.json()
assert isinstance(data["products"], list)
assert data["page"] == 1
assert all("price" in p for p in data["products"])
def test_product_creation(self, auth_client):
"""测试商品创建接口"""
url = f"{self.BASE_URL}/products"
product_data = {
"name": "Premium Headphones",
"description": "Noise cancelling wireless headphones",
"price": 299.99,
"stock": 100,
"category": "electronics"
}
response = auth_client.post(url, json=product_data)
assert response.status_code == 201
product = response.json()
assert product["id"] is not None
assert product["name"] == product_data["name"]
# 验证商品确实已创建
get_response = auth_client.get(f"{url}/{product['id']}")
assert get_response.status_code == 200
6.2 测试报告生成
结合Allure框架生成美观的测试报告:
- 安装依赖:
bash复制pip install pytest-allure
- 添加测试描述和步骤:
python复制import allure
@allure.feature("商品管理")
@allure.story("商品CRUD操作")
class TestProductAPI:
@allure.title("测试创建高价商品")
@allure.severity(allure.severity_level.CRITICAL)
def test_expensive_product(self, auth_client):
"""测试创建价格超过1000元的商品"""
with allure.step("准备测试数据"):
product_data = {
"name": "MacBook Pro",
"price": 1999.99,
"category": "electronics"
}
with allure.step("发送创建请求"):
response = auth_client.post(
f"{self.BASE_URL}/products",
json=product_data
)
with allure.step("验证响应"):
assert response.status_code == 201
product = response.json()
assert product["price"] == product_data["price"]
allure.attach(
response.text,
name="API响应",
attachment_type=allure.attachment_type.JSON
)
- 生成报告:
bash复制pytest --alluredir=./allure-results
allure serve ./allure-results
7. 扩展知识与最佳实践
7.1 OpenAPI/Swagger集成
现代API常用OpenAPI规范描述,可以结合swagger-client进行测试:
python复制from bravado.client import SwaggerClient
# 加载Swagger定义
client = SwaggerClient.from_url(
'https://api.example.com/swagger.json',
config={'validate_responses': True}
)
# 调用API
try:
user = client.users.getUser(userId=1).result()
print(f"User: {user.name}")
except Exception as e:
print(f"API调用失败: {e}")
7.2 性能测试扩展
使用locust进行基于Requests的负载测试:
python复制from locust import HttpUser, task, between
class APIUser(HttpUser):
wait_time = between(1, 3)
@task
def get_products(self):
self.client.get("/products")
@task(3) # 3倍权重
def create_order(self):
self.client.post("/orders", json={
"product_id": 1,
"quantity": 2
})
运行负载测试:
bash复制locust -f locustfile.py
7.3 微服务测试策略
在微服务架构中,API测试需要特别关注:
- 契约测试:使用pact验证服务间契约
python复制from pact import Consumer, Provider
pact = Consumer('Consumer').has_pact_with(Provider('Provider'))
pact.start_service()
(pact
.given('a user exists')
.upon_receiving('a request for user')
.with_request('get', '/users/1')
.will_respond_with(200, body={
'id': 1,
'name': 'John'
}))
with pact:
result = requests.get(pact.uri + '/users/1')
pact.verify()
pact.stop_service()
- 混沌工程:模拟网络问题
python复制from requests_testadapter import TestAdapter
# 模拟慢响应
adapter = TestAdapter(
b'{"slow": "response"}',
status=200,
headers={'Content-Type': 'application/json'},
sleep=5 # 延迟5秒响应
)
session = requests.Session()
session.mount('http://slowapi', adapter)
try:
response = session.get('http://slowapi/test', timeout=3)
except requests.exceptions.Timeout:
print("成功触发超时场景")
8. 持续集成实践
将API测试集成到CI/CD流水线中:
8.1 GitHub Actions配置示例
yaml复制name: API Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Run tests
run: |
pytest --cov=./ --cov-report=xml
- name: Upload coverage
uses: codecov/codecov-action@v1
8.2 Docker化测试环境
创建测试专用的Docker镜像:
dockerfile复制FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["pytest", "-v", "--alluredir=./allure-results"]
运行测试容器:
bash复制docker build -t api-tests .
docker run -v $(pwd)/allure-results:/app/allure-results api-tests
9. 测试数据管理
9.1 工厂模式生成测试数据
python复制from dataclasses import dataclass
import factory
@dataclass
class Product:
id: int
name: str
price: float
class ProductFactory(factory.Factory):
class Meta:
model = Product
id = factory.Sequence(lambda n: n)
name = factory.Faker('word')
price = factory.Faker('pyfloat', positive=True)
# 使用工厂创建测试数据
test_product = ProductFactory()
print(test_product) # 输出类似: Product(id=0, name='dolor', price=123.45)
9.2 数据库夹具管理
使用pytest-django管理测试数据库:
python复制import pytest
from django.urls import reverse
from rest_framework.test import APIClient
@pytest.fixture
def api_client():
return APIClient()
@pytest.fixture
def test_user(django_user_model):
return django_user_model.objects.create_user(
username='testuser',
password='testpass123'
)
def test_authenticated_api(api_client, test_user):
api_client.force_authenticate(user=test_user)
response = api_client.get(reverse('user-detail'))
assert response.status_code == 200
10. 测试覆盖率提升
10.1 边界值分析
python复制import pytest
@pytest.mark.parametrize("price,expected_status", [
(0, 400), # 价格不能为0
(0.01, 201), # 最小正价格
(9999.99, 201), # 常规高价
(10000, 400), # 超过价格上限
(-1, 400), # 负数价格
("abc", 400) # 非数字价格
])
def test_product_price_boundary(auth_client, price, expected_status):
response = auth_client.post(
f"{self.BASE_URL}/products",
json={"name": "Test", "price": price}
)
assert response.status_code == expected_status
10.2 状态转换测试
python复制def test_order_workflow(auth_client):
# 1. 创建订单
create_resp = auth_client.post(
f"{self.BASE_URL}/orders",
json={"product_id": 1, "quantity": 2}
)
assert create_resp.status_code == 201
order_id = create_resp.json()["id"]
# 2. 验证初始状态
get_resp = auth_client.get(f"{self.BASE_URL}/orders/{order_id}")
assert get_resp.status_code == 200
assert get_resp.json()["status"] == "created"
# 3. 支付订单
pay_resp = auth_client.post(
f"{self.BASE_URL}/orders/{order_id}/pay",
json={"payment_method": "credit_card"}
)
assert pay_resp.status_code == 200
assert pay_resp.json()["status"] == "paid"
# 4. 尝试取消已支付订单(应失败)
cancel_resp = auth_client.post(
f"{self.BASE_URL}/orders/{order_id}/cancel"
)
assert cancel_resp.status_code == 400
11. Mock服务实践
11.1 使用responses库模拟API
python复制import responses
import requests
@responses.activate
def test_mocked_api():
# 模拟成功响应
responses.add(
responses.GET,
'https://api.example.com/users/1',
json={'id': 1, 'name': 'John'},
status=200
)
# 模拟错误响应
responses.add(
responses.GET,
'https://api.example.com/users/404',
json={'error': 'Not found'},
status=404
)
# 测试正常情况
resp = requests.get('https://api.example.com/users/1')
assert resp.status_code == 200
assert resp.json()['name'] == 'John'
# 测试错误情况
resp = requests.get('https://api.example.com/users/404')
assert resp.status_code == 404
11.2 使用WireMock实现独立Mock服务
- 启动WireMock服务器:
bash复制docker run -it --rm -p 8080:8080 wiremock/wiremock
- 配置模拟API:
python复制import requests
# 定义模拟端点
mocks = {
"request": {
"method": "GET",
"url": "/api/mock/users"
},
"response": {
"status": 200,
"body": '{"users": [{"id": 1, "name": "Mocked User"}]}',
"headers": {
"Content-Type": "application/json"
}
}
}
# 配置WireMock
requests.post(
"http://localhost:8080/__admin/mappings/new",
json=mocks
)
# 测试模拟API
response = requests.get("http://localhost:8080/api/mock/users")
print(response.json()) # 输出模拟数据
12. 测试代码优化技巧
12.1 使用自定义断言
python复制from requests.models import Response
def assert_response_success(response: Response):
"""验证响应是否成功(2xx)"""
assert 200 <= response.status_code < 300, \
f"Expected success status but got {response.status_code}: {response.text}"
def assert_response_error(response: Response, expected_status: int):
"""验证错误响应"""
assert response.status_code == expected_status, \
f"Expected status {expected_status} but got {response.status_code}"
assert "error" in response.json(), "Error response should contain error field"
# 使用自定义断言
response = requests.get('https://api.example.com/users/1')
assert_response_success(response)
12.2 请求重试装饰器
python复制from functools import wraps
import time
import requests
def retry_request(max_retries=3, delay=1):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
last_exception = None
for attempt in range(max_retries):
try:
return func(*args, **kwargs)
except requests.exceptions.RequestException as e:
last_exception = e
if attempt < max_retries - 1:
time.sleep(delay * (attempt + 1))
raise last_exception
return wrapper
return decorator
@retry_request(max_retries=3, delay=1)
def call_unstable_api():
return requests.get('https://api.example.com/unstable')
# 使用装饰后的函数
try:
response = call_unstable_api()
print(response.json())
except requests.exceptions.RequestException as e:
print(f"API调用最终失败: {e}")
13. 测试报告与文档生成
13.1 自动化生成API文档
使用pytest与swagger-ui结合:
python复制from apispec import APISpec
from apispec_webframeworks.flask import FlaskPlugin
import yaml
# 创建API规范
spec = APISpec(
title="Example API",
version="1.0.0",
openapi_version="3.0.2",
plugins=[FlaskPlugin()],
)
# 在测试中添加API文档
def test_user_api(auth_client):
"""测试用户API
---
get:
description: 获取用户信息
parameters:
- in: path
name: user_id
required: true
schema:
type: integer
responses:
200:
description: 用户详细信息
content:
application/json:
schema:
type: object
properties:
id:
type: integer
name:
type: string
"""
response = auth_client.get(f"{self.BASE_URL}/users/1")
assert response.status_code == 200
# 将测试文档添加到规范
spec.path(path="/users/{user_id}", operations={
"get": test_user_api.__doc__.split("---")[1]
})
# 生成OpenAPI文档
with open("openapi.yaml", "w") as f:
yaml.dump(spec.to_dict(), f)
13.2 测试报告增强
使用pytest-html生成丰富的HTML报告:
bash复制pip install pytest-html
pytest --html=report.html
在报告中添加自定义信息:
python复制def test_with_screenshots(auth_client):
response = auth_client.get(f"{self.BASE_URL}/products")
# 在报告中添加响应信息
pytest_html = pytest.config.pluginmanager.getplugin("html")
pytest_html.extras.append(
pytest_html.extras.json(response.json(), name="API响应")
)
# 添加请求信息
request_info = {
"method": response.request.method,
"url": response.request.url,
"headers": dict(response.request.headers)
}
pytest_html.extras.append(
pytest_html.extras.json(request_info, name="请求详情")
)
14. 性能监控与告警
14.1 响应时间监控
python复制import time
import statistics
from dataclasses import dataclass
from typing import List
@dataclass
class PerformanceResult:
endpoint: str
response_times: List[float]
success_rate: float
def monitor_performance(url, num_requests=10):
"""监控API性能指标"""
times = []
successes = 0
for _ in range(num_requests):
start = time.perf_counter()
try:
response = requests.get(url, timeout=5)
if response.status_code == 200:
successes += 1
except Exception:
pass
finally:
times.append(time.perf_counter() - start)
return PerformanceResult(
endpoint=url,
response_times=times,
success_rate=successes / num_requests
)
# 使用监控
result = monitor_performance("https://api.example.com/products")
print(f"平均响应时间: {statistics.mean(result.response_times):.2f}s")
print(f"成功率: {result.success_rate:.0%}")
14.2 集成Prometheus监控
python复制from prometheus_client import start_http_server, Summary, Gauge
import random
import time
# 创建指标
API_RESPONSE_TIME = Summary(
'api_response_time_seconds',
'API响应时间统计',
['endpoint', 'method']
)
API_SUCCESS_RATE = Gauge(
'api_success_rate',
'API成功率',
['endpoint']
)
def instrumented_request(method, url, **kwargs):
"""带监控的标准请求"""
start_time = time.time()
try:
response = requests.request(method, url, **kwargs)
success = 1 if response.status_code < 400 else 0
duration = time.time() - start_time
# 记录指标
API_RESPONSE_TIME.labels(
endpoint=url,
method=method.upper()
).observe(duration)
API_SUCCESS_RATE.labels(
endpoint=url
).set(success)
return response
except Exception:
API_SUCCESS_RATE.labels(endpoint=url).set(0)
raise
# 启动Prometheus客户端
start_http_server(8000)
# 使用监控的请求
while True:
instrumented_request('GET', 'https://api.example.com/products')
time.sleep(5)
15. 测试策略进阶
15.1 契约测试实践
使用pact-python进行消费者驱动契约测试:
python复制from pact import Consumer, Provider
def test_user_service_contract():
pact = Consumer('WebApp').has_pact_with(
Provider('UserService'),
pact_dir='./pacts'
)
(pact
.given('a user with id 1 exists')
.upon_receiving('a request for user 1')
.with_request(
method='GET',
path='/users/1',
headers={'Accept': 'application/json'}
)
.will_respond_with(
status=200,
headers={'Content-Type': 'application/json'},
body={'id': 1, 'name': 'John'}
))
with pact:
# 这里使用真实客户端代码进行测试
from user_client import get_user
user = get_user('http://localhost:1234', 1)
assert user['name'] == 'John'
# 契约文件将生成在./pacts目录
15.2 混沌工程测试
使用chaostoolkit进行混沌测试:
- 安装chaostoolkit:
bash复制pip install chaostoolkit
- 创建实验文件chaos-experiment.json:
json复制{
"title": "API高延迟测试",
"description": "模拟网络延迟对API的影响",
"steady-state-hypothesis": {
"title": "服务正常运行",
"probes": [
{
"type": "probe",
"name": "api-health-check",
"tolerance": 200,
"provider": {
"type": "http",
"url": "https://api.example.com/health"
}
}
]
},
"method": [
{
"type": "action",
"name": "simulate-network-latency",
"provider": {
"type": "python",
"module": "chaoslib.network",
"func": "network_latency",
"arguments": {
"duration": 300,
"latency": 2000,
"jitter": 500,
"target_host": "api.example.com"
}
}
}
],
"rollbacks": []
}
- 运行混沌实验:
bash复制chaos run chaos-experiment.json
16. 测试数据工厂进阶
16.1 使用Faker生成逼真数据
python复制from faker import Faker
import factory
fake = Faker()
class UserFactory(factory.Factory):
class Meta:
model = dict
id = factory.Sequence(lambda n: n)
name = factory.LazyFunction(fake.name)
email = factory.LazyFunction(fake.email)
address = factory.LazyFunction(fake.address)
phone = factory.LazyFunction(fake.phone_number)
# 生成测试用户
test_users = [UserFactory() for _ in range(5)]
print(test_users)
16.2 关联数据生成
python复制class OrderFactory(factory.Factory):
class Meta:
model = dict
id = factory.Sequence(lambda n: n)
user = factory.SubFactory(UserFactory)
products = factory.List([
factory.Dict({
"product_id": factory.Sequence(lambda n: n),
"name": factory.Faker('word'),
"price": factory.Faker('pyfloat', positive=True, max_value=100),
"quantity": factory.Faker('random_int', min=1, max=5)
}) for _ in range(3) # 每个订单3个商品
])
total = factory.LazyAttribute(
lambda o: sum(p['price'] * p['quantity'] for p in o['products'])
)
# 生成测试订单
test_order = OrderFactory()
print(f"订单总价: {test_order['total']}")
17. 测试环境管理
17.1 使用Docker Compose管理依赖
docker-compose.yml示例:
yaml复制version: '3'
services:
api:
image: my-api:latest
ports:
- "8000:8000"
environment:
- DB_HOST=db
- DB_USER=user
- DB_PASS=pass
db:
image: postgres:13
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=pass
volumes:
- pgdata:/var/lib/postgresql/data
redis:
image: redis:6
volumes:
pgdata:
测试脚本中控制环境:
python复制import docker
import time
def start_test_environment():
client = docker.from_env()
client.containers.run(
"postgres:13",
name="test-db",
environment={
"POSTGRES_USER": "test",
"POSTGRES_PASSWORD": "test"
},
ports={'5432/tcp': 5432},
detach=True
)
# 等待服务就绪
time.sleep(10)
def stop_test_environment():
client = docker.from_env()
container = client.containers.get("test-db")
container.stop()
container.remove()
17.2 测试环境验证
python复制def check_test_environment():
"""验证测试环境是否就绪"""
services = {
"database": {
"check": lambda: requests.get("http://localhost:5432").status_code == 404,
"timeout": 30
},
"api": {
"check": lambda: requests.get("http://localhost:8000/health").status_code == 200,
"timeout": 60
}
}
