Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

testgen-service

Python FastAPI tests license

输入 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 响应体结构校验:字段类型、必填字段、嵌套对象

快速开始

1. 安装

git clone https://github.com/yan2811/testgen_service.git
cd testgen-service
pip install -e ".[dev]"

2. 启动服务

uvicorn app.main:app --reload

访问 http://localhost:8000/docs 查看 Swagger UI。

3. 调用生成

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"
  }'

4. 运行生成的测试

生成的代码保存后,直接 pytest 运行:

pytest test_orders.py -v

使用示例

从 OpenAPI 规范生成

curl -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 命令直接丢进来:

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"]
  }'

作为 Python 库使用

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"])

API 参考

POST /api/v1/generate

参数 类型 必填 默认值 说明
llm_api_key string LLM API key(调用方自行提供)
llm_provider string deepseek deepseekanthropic
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 缓存命中

GET /health

{"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+

License

MIT

About

输入 API 描述(OpenAPI / curl / 自然语言),自动生成 pytest 测试用例,覆盖 happy_path、鉴权、校验、异常、边界值、schema 六大场景。支持 DeepSeek 和 Anthropic 双 LLM 后端。调用方自备 API key,零算力成本。

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages