输入 API 描述,输出生产级 pytest 测试用例。
支持三种输入方式——OpenAPI 规范、curl 命令、自然语言描述。自动覆盖 6 大测试场景,生成的代码可直接运行。
输入一个 OpenAPI yaml:
# 用户管理 API:GET /users, POST /users, GET /users/{id}
# POST 需要 Bearer 鉴权,入参 name/email 必填输出 test_users.py + conftest.py,12 个测试函数:
import pytest
@pytest.mark.id("T001")
@pytest.mark.asyncio
async def test_list_users_returns_200(client):
"""GET /users with valid auth returns 200"""
response = await client.get("/users")
assert response.status_code == 200
@pytest.mark.id("T005")
@pytest.mark.asyncio
async def test_unauthenticated_request_returns_401(client_no_auth):
"""GET /users without auth returns 401"""
response = await client_no_auth.get("/users")
assert response.status_code == 401
@pytest.mark.id("T010")
@pytest.mark.parametrize("payload", [
{"name": "", "email": "x@y.com"},
{"name": "a" * 300, "email": "x@y.com"},
{"name": "<script>alert(1)</script>", "email": "x@x.com"},
])
@pytest.mark.asyncio
async def test_create_user_edge_cases(client, payload):
"""POST /users with edge-case payloads"""
response = await client.post("/users", json=payload)
assert response.status_code in (201, 422)覆盖的测试场景:
| 场景 | 说明 |
|---|---|
| happy_path | 正常请求返回预期 2xx |
| auth | 鉴权失败返回 401/403 |
| validation | 入参校验返回 400/422 |
| error | 服务端错误 500、超时、404 |
| edge_cases | 边界值:空字符串、超长、特殊字符、XSS/SQL 注入 |
| schema | 响应体结构校验:字段类型、必填字段、嵌套对象 |
git clone https://github.com/yan2811/testgen_service.git
cd testgen-service
pip install -e ".[dev]"uvicorn app.main:app --reload访问 http://localhost:8000/docs 查看 Swagger UI。
curl -X POST http://localhost:8000/api/v1/generate \
-H "Content-Type: application/json" \
-d '{
"llm_api_key": "sk-your-deepseek-key",
"input_content": "订单 API:POST /orders 创建订单,请求体包含 item(string, 必填)和 qty(int, 必填),返回 201。GET /orders/{id} 查询订单,返回 200 或 404。需要 Bearer 鉴权。",
"input_format": "natural"
}'生成的代码保存后,直接 pytest 运行:
pytest test_orders.py -vcurl -X POST http://localhost:8000/api/v1/generate \
-H "Content-Type: application/json" \
-d '{
"llm_api_key": "sk-your-key",
"input_content": "openapi: \"3.0.0\"\ninfo:\n title: User API\npaths:\n /users:\n get:\n summary: List users\n responses:\n \"200\":\n description: OK",
"input_format": "openapi",
"auth_type": "bearer",
"auth_credentials": "your-jwt-token"
}'复制浏览器里的 curl 命令直接丢进来:
curl -X POST http://localhost:8000/api/v1/generate \
-H "Content-Type: application/json" \
-d '{
"llm_api_key": "sk-your-key",
"input_content": "curl -X POST https://api.example.com/orders -H \"Authorization: Bearer xxx\" -d '\''{\"item\":\"book\",\"qty\":1}'\''",
"input_format": "curl",
"include_categories": ["happy_path", "auth", "validation"]
}'from app.services.llm_client import LLMClient
from app.services.prompt_builder import build_system_prompt, build_user_message
from app.services.input_parser import parse_input, InputFormat
from app.services.code_validator import validate
from app.schemas.response import TestFile
from app.schemas.request import GenerateTestRequest
req = GenerateTestRequest(
llm_api_key="sk-your-key",
input_content="GET /health returns status ok",
input_format=InputFormat.NATURAL_LANGUAGE,
test_style="httpx_sync",
)
parsed = parse_input(req.input_content, req.input_format)
system = build_system_prompt(req)
user = build_user_message(parsed, req)
client = LLMClient(api_key=req.llm_api_key, provider="deepseek")
result = client.generate(system_prompt=system, user_message=user)
for tf in result["test_files"]:
print(f"# {tf['filename']}")
print(tf["content"])| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
llm_api_key |
string | 是 | — | LLM API key(调用方自行提供) |
llm_provider |
string | 否 | deepseek |
deepseek 或 anthropic |
llm_base_url |
string | 否 | https://api.deepseek.com |
API 地址 |
model |
string | 否 | deepseek-chat |
模型名 |
input_content |
string | 是 | — | API 描述,10–200k 字符 |
input_format |
string | 是 | — | openapi / curl / natural |
base_url |
string | 否 | — | 覆盖测试中的 base URL |
auth_type |
string | 否 | none |
bearer / api_key / basic |
auth_header_name |
string | 否 | — | 自定义鉴权 header |
auth_credentials |
string | 否 | — | 鉴权凭证(日志脱敏) |
test_style |
string | 否 | httpx_async |
httpx_sync / requests |
include_categories |
list | 否 | 全部 | 测试场景子集 |
max_tokens |
int | 否 | 8192 |
512–32000 |
temperature |
float | 否 | 0.1 |
0.0–1.0 |
{
"success": true,
"test_files": [
{"filename": "test_users.py", "content": "import pytest\n..."}
],
"conftest": "import pytest\n...",
"summary": {
"total_functions": 12,
"categories_covered": ["happy_path", "auth", "validation", "error", "edge_cases", "schema"]
},
"validation": {
"is_valid_python": true,
"errors": [],
"warnings": []
},
"usage": {
"input_tokens": 2450,
"output_tokens": 1642,
"cache_read_tokens": 2432,
"cache_write_tokens": 18
}
}test_files— 生成的测试文件列表,content字段是可直接保存的 Python 代码conftest— 共享 fixture(base_url、auth_headers、client)validation.is_valid_python— 是否通过 AST 语法检查usage— token 消耗明细,cache_read_tokens > 0表示 prompt 缓存命中
{"status": "healthy"}客户端请求
│
▼
┌───────────────┐
│ input_parser │ OpenAPI → yaml 解析 → ParsedAPI
│ │ curl → shlex 分词 → ParsedEndpoint
│ │ 自然语言 → 直通,保留原文
└───────┬───────┘
│
▼
┌───────────────┐
│ prompt_builder │ 组装 System prompt(SDET 角色 + JSON输出规范 + 场景模板)
│ │ 组装 User 消息(API 描述 + few-shot 示例 + 鉴权信息)
└───────┬───────┘
│
▼
┌───────────────┐
│ llm_client │ DeepSeek(OpenAI SDK)/ Anthropic(原生 SDK)
│ │ 自动重试 3 次、指数退避
│ │ Prompt cache(Anthropic)减少重复调用成本
└───────┬───────┘
│
▼
┌───────────────┐
│code_validator │ AST 语法解析 → 语法错误检查
│ │ 遍历 def test_* → 缺失检测
│ │ 遍历 assert 语句 → 空测试检测
└───────┬───────┘
│
▼
结构体响应
testgen-service/
├── app/
│ ├── main.py # FastAPI 入口
│ ├── core/
│ │ └── config.py # 服务端配置
│ ├── schemas/
│ │ ├── request.py # 请求 Pydantic 模型
│ │ └── response.py # 响应 Pydantic 模型
│ ├── routers/
│ │ ├── health.py # GET /health
│ │ └── generate.py # POST /api/v1/generate
│ └── services/
│ ├── input_parser.py # 三种输入格式解析
│ ├── prompt_builder.py # Prompt 模板与 few-shot 示例
│ ├── llm_client.py # DeepSeek / Anthropic 双后端
│ └── code_validator.py # AST 代码校验
├── tests/
│ ├── fixtures/
│ │ └── sample_openapi.yaml
│ ├── test_parser.py # 12 个解析测试
│ ├── test_prompt.py # 10 个 prompt 测试
│ ├── test_validator.py # 6 个校验测试
│ └── test_api.py # 6 个 API 集成测试
├── pyproject.toml
├── Dockerfile
└── README.md
python -m pytest tests/ -v共 33 个测试,覆盖解析器、Prompt 构建、代码校验和 API 端点。
| 组件 | 技术 |
|---|---|
| Web 框架 | FastAPI + Pydantic v2 |
| LLM 后端 | DeepSeek(OpenAI SDK)/ Anthropic(原生 SDK) |
| Prompt 缓存 | Anthropic ephemeral cache |
| 输入解析 | PyYAML + shlex + re |
| 代码校验 | Python AST |
| 运行时 | Python 3.11+ |