Skip to content
Back to skills

Api Testing 2

ASecurity

使用 pytest + httpx 进行 API 接口自动化测试的工具包。支持 RESTful API 测试、JWT 认证、参数化测试、断言验证以及测试报告生成。

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 27, 2026
developmentpythonbashfastapitestingapibackendperformance

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 20 files and shows the line behind each finding

Scanned September 27, 2026

npx -y skills add David-Li0406/meta-skill-evloving --skill api-testing-2 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Api Testing 2?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Api Testing 2
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/david-li0406-api-testing-2/badge)](https://www.skillsdirectory.com/skills/david-li0406-api-testing-2)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: api-testing
description: 使用 pytest + httpx 进行 API 接口自动化测试的工具包。支持 RESTful API 测试、JWT 认证、参数化测试、断言验证以及测试报告生成。
---

# API 接口自动化测试

要测试后端 API 接口,请编写原生的 Python pytest + httpx 脚本。

**可用辅助脚本**:
- `scripts/api_client.py` - API 客户端封装(支持认证、请求、响应处理)
- `scripts/with_backend.py` - 管理后端服务器生命周期

**务必先使用 `--help` 运行脚本** 以查看用法。在你先尝试直接运行脚本并确认必须定制之前,不要阅读源码。这些脚本可能非常庞大,会污染你的上下文窗口。

## 决策树:选择你的方法

```
用户任务 → 是否有 OpenAPI/Swagger 文档?
    ├─ 是 → 读取 /docs 或 /openapi.json 获取接口定义
    │         ├─ 成功 → 根据接口定义编写测试脚本
    │         └─ 失败 → 手动分析接口(见下)
    │
    └─ 否 → 后端服务是否已在运行?
        ├─ 否 → 运行:python scripts/with_backend.py --help
        │        然后使用该助手启动服务 + 编写测试脚本
        │
        └─ 是 → 先探测,后测试:
            1. 获取 OpenAPI 文档:GET /openapi.json
            2. 分析接口路径、方法、参数
            3. 编写测试用例覆盖正向/异常场景
            4. 执行测试并验证响应
```

## 项目服务配置

本项目的服务端口配置:

| 服务 | 地址 | 说明 |
|------|------|------|
| 后端 API | `http://localhost:5000` | FastAPI 服务 |
| API 文档 | `http://localhost:5000/docs` | Swagger UI |
| OpenAPI | `http://localhost:5000/openapi.json` | OpenAPI 规范 |

## 示例:使用 with_backend.py

要启动后端服务,先运行 `--help`,然后使用该助手:

**启动后端服务:**
```bash
python scripts/with_backend.py --server "python run.py" --port 5000 -- pytest tests/api/ -v
```

**指定工作目录:**
```bash
python scripts/with_backend.py \
  --server "python run.py" \
  --port 5000 \
  --cwd platform-fastapi-server \
  -- pytest tests/api/test_login.py -v
```

## 示例:使用 api_client.py

编写测试脚本时,使用封装好的 API 客户端:

```python
from scripts.api_client import APIClient

# 创建客户端
client = APIClient(base_url="http://localhost:5000")

# 登录获取 Token
client.login("admin", "admin123")

# 发送请求
response = client.get("/user/queryById", params={"id": 1})
assert response.status_code == 200

data = response.json()
assert data["code"] == 200
assert data["data"]["username"] == "admin"

# 关闭客户端
client.close()
```

## "先探测,后测试"模式

1. **获取接口文档**:
   ```python
   response = client.get("/openapi.json")
   api_spec = response.json()
   paths = api_spec["paths"]  # 所有接口路径
   ```

2. **分析接口定义**:
   ```python
   # 获取某个接口的详细信息
   login_spec = paths["/login"]["post"]
   request_body = login_spec["requestBody"]
   responses = login_spec["responses"]
   ```

3. **编写测试用例**:
   ```python
   def test_login_success():
       response = client.post("/login", json={
           "username": "admin",
           "password": "admin123"
       })
       assert response.json()["code"] == 200
   ```

## pytest 测试脚本模板

```python
# tests/api/test_user.py
import pytest
from scripts.api_client import APIClient

class TestUserAPI:
    """用户管理接口测试"""
    
    @pytest.fixture(autouse=True)
    def setup(self):
        """测试前置:创建客户端并登录"""
        self.client = APIClient()
        self.client.login()
        yield
        self.client.close()
    
    # ========== 正向测试 ==========
    
    def test_query_user_list(self):
        """查询用户列表"""
        response = self.client.post("/user/queryByPage", json={
            "pageNum": 1,
            "pageSize": 10
        })
        assert response.status_code == 200
        data = response.json()
        assert data["code"] == 200
        assert "list" in data["data"]
    
    # ========== 异常测试 ==========
    
    def test_query_user_not_found(self):
        """查询不存在的用户"""
        response = self.client.get("/user/queryById", params={"id": 99999})
        data = response.json()
        assert data["data"] is None or data["code"] != 200
    
    # ========== 参数化测试 ==========
    
    @pytest.mark.parametrize("username,password,expected", [
        ("admin", "admin123", True),      # 正确凭证
        ("admin", "wrong", False),         # 错误密码
        ("", "admin123", False),           # 空用户名
    ])
    def test_login_scenarios(self, username, password, expected):
        """登录场景参数化测试"""
        client = APIClient()
        response = client.post("/login", json={
            "username": username,
            "password": password
        })
        data = response.json()
        assert (data["code"] == 200) == expected
        client.close()
```

## 常见陷阱

❌ 忘记在请求头中添加 Token
✅ 使用 `client.login()` 自动管理 Token

❌ 硬编码测试数据导致用例相互依赖
✅ 每个测试用例独立创建和清理数据

❌ 只测试正向场景
✅ 覆盖正向、异常、边界值场景

❌ 忽略响应状态码,只检查业务 code
✅ 同时验证 HTTP 状态码和业务响应码

## 最佳实践

- **使用 fixture 管理客户端生命周期** - 避免重复创建/销毁客户端
- **参数化测试** - 使用 `@pytest.mark.parametrize` 减少重复代码
- **数据隔离** - 测试数据使用唯一标识,测试后清理
- **断言明确** - 验证状态码、响应结构、关键字段
- **分层组织** - 按模块组织测试文件,便于维护

## 测试执行命令

```bash
# 运行所有 API 测试
pytest tests/api/ -v

# 运行指定测试文件
pytest tests/api/test_login.py -v

# 运行指定测试类/方法
pytest tests/api/test_user.py::TestUserAPI::test_query_user_list -v

# 生成 HTML 报告
pytest tests/api/ -v --html=reports/api_report.html

# 并行执行
pytest tests/api/ -v -n auto

# 失败重试
pytest tests/api/ -v --reruns 2
```

## 参考文件

- **examples/** - 展示常见模式的示例:
  - `basic_crud_test.py` - 基础 CRUD 接口测试
  - `auth_test.py` - 认证授权测试
  - `parametrize_test.py` - 参数化测试示例
  - `data_driven_test.py` - 数据驱动测试

## 完整教程

**`examples/tutorial/`** - 9个渐进式示例,从入门到高级:

### 入门级(1小时)
| 示例 | 目录 | 学习内容 |
|-----|------|---------|
| 01 | `beginner/01_basic_request/` | GET/POST 请求、响应获取 |
| 02 | `beginner/02_response_validation/` | 状态码、JSON 结构验证 |
| 03 | `beginner/03_authentication/` | 登录、Token 认证 |

### 中级(1.5小时)
| 示例 | 目录 | 学习内容 |
|-----|------|---------|
| 04 | `intermediate/04_crud_testing/` | CRUD 接口测试、数据清理 |
| 05 ⭐ | `intermediate/05_parametrize/` | **参数化测试(重点)** |
| 06 ⭐ | `intermediate/06_data_driven/` | **数据驱动测试(重点)** |

### 高级(2小时)
| 示例 | 目录 | 学习内容 |
|-----|------|---------|
| 07 | `advanced/07_contract_testing/` | OpenAPI 契约验证 |
| 08 | `advanced/08_performance/` | 响应时间、并发测试 |
| 09 ⭐ | `advanced/09_comprehensive/` | **完整测试套件(重点)** |

### 运行教程

```bash
cd examples/tutorial

# 查看所有命令
make help

# 运行特定示例
make 01  # 基础请求
make 05  # 参数化测试(重点)
make 09  # 综合套件(重点)

# 运行所有示例
make all
```

### 核心知识点速查

**参数化测试(重要):**
```python
@pytest.mark.parametrize("username,password,expected", [
    ("admin", "admin123", True),   # 正确凭证
    ("admin", "wrong", False),      # 错误密码
    ("", "admin123", False),        # 空用户名
])
def test_login(self, username, password, expected):
    response = client.post("/login", json={
        "username": username,
        "password": password
    })
    actual = response.json()["code"] == 200
    assert actual == expected
```

**数据驱动测试(重要):**
```python
TEST_DATA = [
    {"case_id": "TC_001", "username": "admin", "password": "admin123", "expected": True},
    {"case_id": "TC_002", "username": "admin", "password": "wrong", "expected": False},
]

@pytest.mark.parametrize("case", TEST_DATA, ids=lambda x: x["case_id"])
def test_login(self, case):
    response = client.post("/login", json={
        "username": case["username"],
        "password": case["password"]
    })
    assert (response.json()["code"] == 200) == case["expected"]
```

**Fixture 数据清理:**
```python
@pytest.fixture
def cleanup_users(api_client):
    created_ids = []
    yield created_ids
    # 测试结束后自动清理
    for id in created_ids:
        api_client.delete(f"/user/delete", params={"id": id})
```

详细内容请查看 `examples/tutorial/README.md`。

Files in this skill

  • SKILL.md9 KB
  • examples/auth_test.py6.3 KB
  • examples/basic_crud_test.py5.7 KB
  • examples/data_driven_test.py8.5 KB
  • examples/parametrize_test.py6.9 KB
  • examples/tutorial/Makefile2.9 KB
  • examples/tutorial/README.md18.1 KB
  • examples/tutorial/advanced/07_contract_testing/test_contract.py9.5 KB
  • examples/tutorial/advanced/08_performance/test_performance.py10.6 KB
  • examples/tutorial/advanced/09_comprehensive/conftest.py4.3 KB
  • examples/tutorial/advanced/09_comprehensive/test_auth.py3 KB
  • examples/tutorial/advanced/09_comprehensive/test_project.py5.4 KB
  • examples/tutorial/advanced/09_comprehensive/test_user.py5.1 KB
  • examples/tutorial/beginner/01_basic_request/test_basic.py4.4 KB
  • examples/tutorial/beginner/02_response_validation/test_validation.py6.4 KB
  • examples/tutorial/beginner/03_authentication/test_auth.py6.4 KB
  • examples/tutorial/intermediate/04_crud_testing/test_crud.py10.4 KB
  • examples/tutorial/intermediate/05_parametrize/test_parametrize.py8.7 KB
  • examples/tutorial/intermediate/06_data_driven/test_data_driven.py11.8 KB
  • scripts/api_client.py9.3 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…