共计 3236 个字符,预计需要花费 9 分钟才能阅读完成。
为什么 ChatGPT API 测试与众不同
刚接触 ChatGPT API 测试时,我发现它和普通 HTTP 接口测试有三大差异点:

- 对话状态维护 :每个对话都有上下文关联,就像人类聊天需要记住前面说过什么
- token 消耗动态计算 :每次请求的 token 使用量直接影响计费,需要特别监控
- 流式响应处理 :当 stream=True 时,数据是分块传输的,传统断言方式会失效
手工测试 vs 自动化测试
用 Postman 测试 ChatGPT 就像用筷子吃牛排——能行但不专业:
- 手工测试优点:
- 快速验证单次接口响应
-
直观看到返回的 JSON 结构
-
自动化测试优势:
- 自动维护对话上下文
- 批量执行边界值测试
- 实时统计 token 消耗
- 自动生成可追溯的测试报告
实战:搭建测试框架
1. API 调用封装
先安装必要依赖:
pip install requests pytest
核心封装代码(chatgpt_client.py):
import os
from typing import Iterator, Dict
import requests
class ChatGPTTestClient:
def __init__(self, api_key: str):
self.base_url = "https://api.openai.com/v1/chat/completions"
self.headers = {"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
# 初始化对话历史
self.conversation_history = []
def send_message(
self,
prompt: str,
stream: bool = False
) -> Iterator[Dict] | Dict:
"""发送消息并处理流式 / 非流式响应"""
self.conversation_history.append({"role": "user", "content": prompt})
payload = {
"model": "gpt-3.5-turbo",
"messages": self.conversation_history,
"stream": stream
}
response = requests.post(
self.base_url,
headers=self.headers,
json=payload,
timeout=30
)
if stream:
return self._handle_stream_response(response)
else:
return self._handle_normal_response(response)
def _handle_normal_response(self, response: requests.Response) -> Dict:
"""处理普通响应"""
response.raise_for_status()
data = response.json()
assistant_reply = data["choices"][0]["message"]
self.conversation_history.append(assistant_reply)
return data
def _handle_stream_response(self, response: requests.Response) -> Iterator[Dict]:
"""处理流式响应"""
response.raise_for_status()
for chunk in response.iter_lines():
if chunk:
yield json.loads(chunk.decode("utf-8").lstrip("data:"))
2. Pytest 测试用例设计
测试文件示例(test_chatgpt.py):
import pytest
from chatgpt_client import ChatGPTTestClient
@pytest.fixture(scope="module")
def client():
"""共享测试客户端"""
return ChatGPTTestClient(os.getenv("OPENAI_API_KEY"))
# 参数化测试不同长度的输入
@pytest.mark.parametrize("prompt", [
"你好",
"请用 200 字介绍量子力学",
"a" * 1000 # 边界值测试
])
def test_single_turn_chat(client, prompt):
"""测试单轮对话"""
response = client.send_message(prompt)
assert "choices" in response
assert len(response["choices"][0]["message"]["content"]) > 0
# 测试上下文保持
def test_multi_turn_chat(client):
"""测试多轮对话记忆"""
client.send_message("我的名字是张三")
response = client.send_message("我刚才说我叫什么名字?")
assert "张三" in response["choices"][0]["message"]["content"]
3. 对话上下文方案对比
方案 A:session_id 跟踪
- 优点:服务端自动维护状态
- 缺点:无法在测试中断后恢复对话
方案 B:内存缓存(示例代码采用)
- 优点:
- 完全掌控对话历史
- 支持测试失败后重建上下文
- 缺点:
- 需要自行处理 token 限制
- 大对话集占用内存
生产环境避坑指南
1. 异步调用超时设置
ChatGPT API 有时响应较慢,必须设置双重超时:
# 在 requests.post() 中设置
response = requests.post(
url,
timeout=(10, 30) # 连接超时 10 秒,读取超时 30 秒
)
2. 敏感数据过滤
测试报告中的 API 密钥必须脱敏:
# 在 pytest 钩子中处理
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):
report = (yield).get_result()
if report.failed:
report.longrepr = str(report.longrepr).replace(os.getenv("OPENAI_API_KEY"),
"***"
)
3. 测试幂等性设计
避免测试互相影响的方法:
- 每个测试用例使用独立对话 ID
- 测试前后清理历史记录
- 使用 pytest 的 tmpdir 处理测试数据
@pytest.fixture
def clean_client(client):
"""每次测试后清空历史"""
yield client
client.conversation_history = []
延伸思考
多轮对话断言机制
可以考虑:
1. 关键词命中检查
2. 语义相似度对比(使用 sentence-transformers)
3. 意图识别验证
模拟 API 限流
使用 unittest.mock 模拟 429 响应:
from unittest.mock import patch
def test_rate_limit():
with patch("requests.post") as mock_post:
mock_post.return_value.status_code = 429
response = client.send_message("test")
assert "rate limit" in response["error"]["message"]
总结建议
建议从简单测试用例开始,逐步增加:
1. 基础功能验证 → 2. 异常场景覆盖 → 3. 性能监控
可以结合 Jenkins 或 GitHub Actions 实现持续测试,每次代码提交都自动验证 ChatGPT 接口的兼容性。对于企业级应用,建议增加对话质量评估模块,用自动化手段检查回复的相关性和安全性。
正文完
