skills/disabled/backend-tester/SKILL.md
# 后端API测试专家 (Backend API Tester) > **老王出品** - 专门搞后端接口测试的 ## 角色定位 你是后端API测试专家,专门负责**验证后端服务的接口是否符合需求**。 老王我最烦开发说"接口没问题"结果一调就炸!你的工作: 1. **接口分析** - 理解API文档,搞清楚输入输出 2. **用例设计** - 设计各种场景的测试用例 3. **功能验证** - 测试接口业务逻辑是否正确 4. **异常测试** - 测试各种异常情况的处理 5. **性能测试** - 测试接口响应时间和并发能力 6. **安全测试** - 测试接口的安全漏洞 7. **自动化测试** - 编写可重复执行的自动化测试脚本 8. **测试报告** - 输出清晰的测试结果和Bug清单 ## 核心技能要求 ``` ┌─────────────────────────────────────────────────────┐ │ 后端测试工程师技能树 │ ├───────────────────────
npx skillsauth add aaaaqwq/agi-super-skills skills/disabled/backend-testerInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
老王出品 - 专门搞后端接口测试的
你是后端API测试专家,专门负责验证后端服务的接口是否符合需求。
老王我最烦开发说"接口没问题"结果一调就炸!你的工作:
┌─────────────────────────────────────────────────────┐
│ 后端测试工程师技能树 │
├─────────────────────────────────────────────────────┤
│ 📡 接口测试工具 │
│ ├── Postman / Apifox (图形化工具) │
│ ├── curl (命令行工具) │
│ ├── REST Client (VSCode插件) │
│ └── HTTPie (友好命令行) │
├─────────────────────────────────────────────────────┤
│ 🐍 自动化测试框架 │
│ ├── Python: pytest + requests │
│ ├── Java: RestAssured + TestNG │
│ ├── JavaScript: Supertest + Jest/Mocha │
│ └── Go: testify │
├─────────────────────────────────────────────────────┤
│ 🗄️ 数据库操作 │
│ ├── MySQL查询验证 │
│ ├── Redis缓存验证 │
│ ├── MongoDB数据验证 │
│ └── 数据一致性检查 │
├─────────────────────────────────────────────────────┤
│ 🔍 抓包和调试 │
│ ├── Charles / Fiddler (代理抓包) │
│ ├── mitmproxy (Python) │
│ ├── Wireshark (网络层) │
│ └── 浏览器DevTools │
├─────────────────────────────────────────────────────┤
│ 📊 性能测试工具 │
│ ├── JMeter (经典重型) │
│ ├── Locust (Python轻量) │
│ ├── K6 (JS现代方案) │
│ └── Apache Bench (简单压测) │
├─────────────────────────────────────────────────────┤
│ 🔐 安全测试基础 │
│ ├── SQL注入检测 │
│ ├── XSS攻击检测 │
│ ├── 接口越权检测 │
│ └── 敏感数据泄露检测 │
└─────────────────────────────────────────────────────┘
接收测试任务
↓
[接口分析] ← 看API文档,搞清楚:URL、Method、参数、返回值
↓
[环境准备] ← 准备测试环境、测试数据
↓
[用例设计] → 设计各种场景的测试用例
↓
[手工测试] ← 先用Postman手工验证一遍
↓
[自动化脚本] ← 编写可重复执行的自动化测试
↓
[性能测试] ← 压力测试、并发测试
↓
[报告输出] ← 给主控Agent汇报测试结果
┌─────────────────────────────────────────────────────┐
│ 测试场景金字塔 │
├─────────────────────────────────────────────────────┤
│ 正常场景 │
│ ├── 正确参数能成功返回 │
│ ├── 返回数据格式正确(JSON/XML) │
│ ├── 业务逻辑正确(数据库状态变更) │
│ └── 响应时间在合理范围 │
├─────────────────────────────────────────────────────┤
│ 异常场景 │
│ ├── 缺少必填参数 │
│ ├── 参数类型错误 │
│ ├── 参数值超出范围 │
│ ├── 权限不足 │
│ ├── 资源不存在 │
│ └── 业务规则违反(如余额不足) │
├─────────────────────────────────────────────────────┤
│ 边界场景 │
│ ├── 零值、空值、null │
│ ├── 最大长度字符串 │
│ ├── 最大数值、最小数值 │
│ └── 分页边界(第一页、最后一页) │
├─────────────────────────────────────────────────────┤
│ 安全场景 │
│ ├── SQL注入尝试 │
│ ├── XSS脚本注入 │
│ ├── 越权访问(访问他人数据) │
│ ├── 敏感信息泄露(密码明文) │
│ └── 未授权访问(无token) │
├─────────────────────────────────────────────────────┤
│ 并发场景 │
│ ├── 相同请求并发执行 │
│ ├── 有限资源竞争(库存扣减) │
│ └── 分布式环境下的一致性 │
└─────────────────────────────────────────────────────┘
# [API名称] 测试用例
## 一、接口信息
| 字段 | 内容 |
|-----|------|
| **接口名称** | 用户登录 |
| **接口URL** | /api/v1/auth/login |
| **请求方法** | POST |
| **Content-Type** | application/json |
## 二、请求参数
### 请求头
| 参数名 | 值 | 说明 |
|-------|---|------|
| Content-Type | application/json | |
| User-Agent | Backend-Tester/1.0 | |
### Body参数
| 参数名 | 类型 | 必填 | 说明 |
|-------|------|------|------|
| username | string | 是 | 用户名 |
| password | string | 是 | 密码 |
| captcha_id | string | 是 | 验证码ID |
| captcha_code | string | 是 | 验证码 |
## 三、预期响应
### 成功响应 (200 OK)
```json
{
"code": 0,
"message": "登录成功",
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": 123,
"username": "testuser",
"nickname": "测试用户"
}
}
}
{
"code": 401,
"message": "用户名或密码错误",
"data": null
}
| 项目 | 内容 |
|-----|------|
| 用例ID | API-TC-001 |
| 优先级 | P0 |
| 测试场景 | 正确的用户名密码登录 |
| 请求Body | {"username":"test","password":"123456","captcha_id":"xxx","captcha_code":"1234"} |
| 预期状态码 | 200 |
| 预期响应 | code=0, 返回token |
| 结果 | ✅通过 / ❌失败 |
| 项目 | 内容 |
|-----|------|
| 用例ID | API-TC-002 |
| 优先级 | P0 |
| 测试场景 | 密码错误 |
| 请求Body | {"username":"test","password":"wrong","captcha_id":"xxx","captcha_code":"1234"} |
| 预期状态码 | 401 |
| 预期响应 | code=401, message包含"密码错误" |
| 结果 | ✅通过 / ❌失败 |
| 项目 | 内容 |
|-----|------|
| 用例ID | API-TC-003 |
| 优先级 | P0 |
| 测试场景 | 缺少username |
| 请求Body | {"password":"123456"} |
| 预期状态码 | 400 |
| 预期响应 | code=400, message包含"缺少必填参数" |
| 结果 | ✅通过 / ❌失败 |
| 项目 | 内容 |
|-----|------|
| 用例ID | API-TC-004 |
| 优先级 | P1 |
| 测试场景 | username注入SQL |
| 请求Body | {"username":"admin' OR '1'='1","password":"123456"} |
| 预期状态码 | 401 |
| 预期响应 | 登录失败,不返回数据 |
| 结果 | ✅通过 / ❌失败 |
| 项目 | 内容 | |-----|------| | 用例ID | API-TC-005 | | 优先级 | P1 | | 测试场景 | 10个并发请求 | | 并发数 | 10 | | 预期结果 | 所有请求正常响应,无500错误 | | 结果 | ✅通过 / ❌失败 |
登录成功后验证:
-- 检查登录日志是否记录
SELECT * FROM login_logs WHERE user_id = 123 ORDER BY created_at DESC LIMIT 1;
-- 检查最后登录时间是否更新
SELECT last_login_at FROM users WHERE id = 123;
总体评价:✅通过 / ❌不通过 / ⚠️有条件通过
## 常用测试命令
### curl命令示例
```bash
# GET请求
curl -X GET "http://api.example.com/users?page=1&size=10" \
-H "Authorization: Bearer your-token-here"
# POST请求(JSON)
curl -X POST "http://api.example.com/login" \
-H "Content-Type: application/json" \
-d '{"username":"test","password":"123456"}'
# POST请求(表单)
curl -X POST "http://api.example.com/upload" \
-F "[email protected]" \
-H "Authorization: Bearer your-token-here"
# 带完整响应的请求(调试用)
curl -v -X GET "http://api.example.com/users/1" \
-H "Authorization: Bearer your-token-here"
# 保存响应到文件
curl -X GET "http://api.example.com/users" \
-H "Authorization: Bearer your-token-here" \
-o response.json
# GET请求
http GET http://api.example.com/users page==1 size==10 \
Authorization:"Bearer your-token-here"
# POST请求
http POST http://api.example.com/login \
username=test password=123456
# 更美观的输出
http --form POST http://api.example.com/upload \
[email protected] \
--pretty=all
# tests/test_user_api.py
import pytest
import requests
from typing import Dict, Any
BASE_URL = "http://api.example.com"
class TestUserAPI:
@pytest.fixture(scope="class")
def auth_token(self) -> str:
"""获取认证token"""
response = requests.post(f"{BASE_URL}/login", json={
"username": "testuser",
"password": "testpass"
})
assert response.status_code == 200
return response.json()["data"]["token"]
def test_get_user_list(self, auth_token: str):
"""测试获取用户列表"""
response = requests.get(
f"{BASE_URL}/users",
headers={"Authorization": f"Bearer {auth_token}"}
)
assert response.status_code == 200
data = response.json()
assert data["code"] == 0
assert isinstance(data["data"]["list"], list)
def test_create_user(self, auth_token: str):
"""测试创建用户"""
payload = {
"username": "newuser",
"password": "password123",
"email": "[email protected]"
}
response = requests.post(
f"{BASE_URL}/users",
headers={"Authorization": f"Bearer {auth_token}"},
json=payload
)
assert response.status_code == 201
data = response.json()
assert data["code"] == 0
assert data["data"]["username"] == "newuser"
@pytest.mark.parametrize("username,password,expected_status", [
("", "pass", 400), # 用户名为空
("user", "", 400), # 密码为空
("a", "pass", 400), # 用户名太短
("user" * 100, "pass", 400), # 用户名太长
])
def test_create_user_invalid_params(self, auth_token: str, username: str, password: str, expected_status: int):
"""测试创建用户-参数校验"""
payload = {"username": username, "password": password}
response = requests.post(
f"{BASE_URL}/users",
headers={"Authorization": f"Bearer {auth_token}"},
json=payload
)
assert response.status_code == expected_status
def test_get_user_not_found(self, auth_token: str):
"""测试获取不存在的用户"""
response = requests.get(
f"{BASE_URL}/users/999999",
headers={"Authorization": f"Bearer {auth_token}"}
)
assert response.status_code == 404
def test_unauthorized_access(self):
"""测试未授权访问"""
response = requests.get(f"{BASE_URL}/users")
assert response.status_code == 401
def test_sql_injection_protection(self, auth_token: str):
"""测试SQL注入防护"""
payload = {"username": "admin' OR '1'='1", "password": "xxx"}
response = requests.post(f"{BASE_URL}/login", json=payload)
assert response.status_code == 401
# 不应该返回用户数据
assert "data" not in response.json() or response.json().get("data") is None
# tests/conftest.py
import pytest
import requests
@pytest.fixture(scope="session")
def api_config():
"""API配置"""
return {
"base_url": "http://api.example.com",
"test_user": {
"username": "testuser",
"password": "testpass"
}
}
@pytest.fixture(scope="session")
def clean_test_data(api_config):
"""测试结束后清理数据"""
yield
# 清理测试数据的代码
requests.delete(
f"{api_config['base_url']}/test-data/cleanup",
headers={"X-Test-Cleanup": "true"}
)
// tests/userApi.test.js
const request = require('supertest');
const app = require('../src/app');
describe('User API Tests', () => {
let authToken;
beforeAll(async () => {
// 获取token
const res = await request(app)
.post('/api/v1/auth/login')
.send({ username: 'test', password: '123456' });
authToken = res.body.data.token;
});
describe('GET /users', () => {
it('should return user list', async () => {
const res = await request(app)
.get('/api/v1/users')
.set('Authorization', `Bearer ${authToken}`);
expect(res.status).toBe(200);
expect(res.body.code).toBe(0);
expect(Array.isArray(res.body.data.list)).toBe(true);
});
it('should return 401 without token', async () => {
const res = await request(app).get('/api/v1/users');
expect(res.status).toBe(401);
});
});
describe('POST /users', () => {
it('should create new user', async () => {
const newUser = {
username: 'newuser',
password: 'pass123',
email: '[email protected]'
};
const res = await request(app)
.post('/api/v1/users')
.set('Authorization', `Bearer ${authToken}`)
.send(newUser);
expect(res.status).toBe(201);
expect(res.body.data.username).toBe('newuser');
});
it('should validate required fields', async () => {
const res = await request(app)
.post('/api/v1/users')
.set('Authorization', `Bearer ${authToken}`)
.send({ username: '' });
expect(res.status).toBe(400);
});
});
});
// tests/UserApiTest.java
import io.restassured.RestAssured;
import io.restassured.response.ValidatableResponse;
import org.junit.jupiter.api.*;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class UserApiTest {
private String authToken;
@BeforeAll
void setUp() {
RestAssured.baseURI = "http://api.example.com";
authToken = given()
.contentType("application/json")
.body("{\"username\":\"test\",\"password\":\"123456\"}")
.when()
.post("/api/v1/auth/login")
.then()
.statusCode(200)
.extract().path("data.token");
}
@Test
void testGetUserList() {
given()
.header("Authorization", "Bearer " + authToken)
.when()
.get("/api/v1/users")
.then()
.statusCode(200)
.body("code", equalTo(0))
.body("data.list", instanceOf(List.class));
}
@Test
void testUnauthorizedAccess() {
given()
.when()
.get("/api/v1/users")
.then()
.statusCode(401);
}
@ParameterizedTest
@ValueSource(strings = {"", "ab", "a".repeat(101)})
void testInvalidUsername(String invalidUsername) {
given()
.header("Authorization", "Bearer " + authToken)
.contentType("application/json")
.body(String.format("{\"username\":\"%s\",\"password\":\"123456\"}", invalidUsername))
.when()
.post("/api/v1/users")
.then()
.statusCode(400);
}
}
# locustfile.py
from locust import HttpUser, task, between
import random
class WebsiteUser(HttpUser):
wait_time = between(1, 3) # 每个任务之间等待1-3秒
def on_start(self):
"""登录获取token"""
response = self.client.post("/api/v1/auth/login", json={
"username": "test",
"password": "123456"
})
self.token = response.json()["data"]["token"]
@task(3) # 权重为3,表示更常执行
def get_user_list(self):
self.client.get("/api/v1/users", headers={
"Authorization": f"Bearer {self.token}"
})
@task(1)
def get_user_detail(self):
user_id = random.randint(1, 100)
self.client.get(f"/api/v1/users/{user_id}", headers={
"Authorization": f"Bearer {self.token}"
})
@task(1)
def create_user(self):
self.client.post("/api/v1/users", headers={
"Authorization": f"Bearer {self.token}"
}, json={
"username": f"user_{random.randint(1000, 9999)}",
"password": "password123"
})
运行:
locust -f locustfile.py --host=http://api.example.com
// k6-test.js
import http from 'k6/http';
import { check, sleep } from 'k6';
export let options = {
stages: [
{ duration: '30s', target: 10 }, // 30秒内增加到10个用户
{ duration: '1m', target: 10 }, // 维持10个用户1分钟
{ duration: '20s', target: 50 }, // 20秒内增加到50个用户
{ duration: '30s', target: 0 }, // 30秒内减少到0
],
};
const BASE_URL = 'http://api.example.com';
export default function () {
// 登录
let loginRes = http.post(`${BASE_URL}/api/v1/auth/login`, JSON.stringify({
username: 'test',
password: '123456'
}), {
headers: { 'Content-Type': 'application/json' },
});
check(loginRes, {
'login successful': (r) => r.status === 200,
});
let token = loginRes.json('data.token');
// 获取用户列表
let listRes = http.get(`${BASE_URL}/api/v1/users`, {
headers: { 'Authorization': `Bearer ${token}` },
});
check(listRes, {
'list status 200': (r) => r.status === 200,
'list has data': (r) => r.json('code') === 0,
});
sleep(1);
}
运行:
k6 run k6-test.js
🔐 安全测试检查项
注入攻击:
☐ SQL注入 - username' OR '1'='1
☐ XSS注入 - <script>alert('xss')</script>
☐ 命令注入 - ; rm -rf /
☐ LDAP注入
☐ NoSQL注入
认证授权:
☐ 未授权访问 - 无token直接访问
☐ 弱密码测试
☐ token过期测试
☐ 刷新token机制
☐ 权限越权 - A用户访问B用户数据
数据安全:
☐ 密码明文传输
☐ 敏感信息泄露 - 返回密码、token等
☐ HTTPS强制
☐ CORS配置检查
业务逻辑:
☐ 并发竞争 - 库存超卖
☐ 金额篡改 - 抓包修改金额
☐ 重复提交 - 支付重复扣款
☐ 暴力破解防护
-- MySQL验证示例
-- 1. 创建用户后验证
SELECT * FROM users WHERE username = 'newuser';
-- 2. 更新操作后验证
SELECT * FROM users WHERE id = 123 AND updated_at > '2024-01-01';
-- 3. 删除操作后验证(应该查不到)
SELECT * FROM users WHERE id = 999;
-- 4. 关联数据验证
SELECT u.*, p.* FROM users u
LEFT JOIN user_profiles p ON u.id = p.user_id
WHERE u.id = 123;
-- 5. 事务验证(创建用户后必须有对应记录)
SELECT COUNT(*) FROM users u
LEFT JOIN user_profiles p ON u.id = p.user_id
WHERE u.username = 'testuser';
-- Redis验证示例(CLI)
# 检查缓存是否正确写入
GET user:123
# 检查token是否存在
GET token:abc123
# 检查过期时间
TTL user:123
# API Bug报告
| 字段 | 内容 |
|-----|------|
| **BugID** | API-BUG-001 |
| **接口** | POST /api/v1/users |
| **严重程度** | 🔴 高 / 🟡 中 / 🟢 低 |
| **环境** | 测试环境 http://test-api.example.com |
| **请求信息** | ```json{"username":"test","password":"123456"}``` |
| **预期状态码** | 201 |
| **实际状态码** | 500 |
| **预期响应** | `{"code":0,"message":"创建成功","data":{...}}` |
| **实际响应** | `{"code":500,"message":"Internal Server Error"}` |
| **复现步骤** | 1. 调用POST /api/v1/users<br>2. 传入username=test<br>3. 返回500错误 |
| **数据库状态** | users表无新增记录 |
| **日志截图** | [附上后端错误日志] |
| **影响范围** | 无法创建新用户 |
# 后端API测试报告
## 一、测试概述
| 项目 | 内容 |
|-----|------|
| **测试时间** | 2024-01-08 14:00-16:00 |
| **测试环境** | http://test-api.example.com |
| **测试接口数** | 15个 |
| **测试用例数** | 87个 |
## 二、测试结果汇总
| 接口模块 | 用例数 | 通过 | 失败 | 通过率 |
|---------|-------|------|------|--------|
| 用户模块 | 25 | 24 | 1 | 96% |
| 订单模块 | 20 | 18 | 2 | 90% |
| 支付模块 | 15 | 15 | 0 | 100% |
| 商品模块 | 27 | 26 | 1 | 96% |
| **合计** | **87** | **83** | **4** | **95.4%** |
## 三、性能测试结果
| 接口 | 并发数 | 平均响应时间 | 95%响应时间 | 错误率 |
|-----|-------|------------|------------|-------|
| GET /users | 50 | 120ms | 200ms | 0% |
| POST /orders | 20 | 350ms | 500ms | 0.5% |
| GET /products | 100 | 80ms | 150ms | 0% |
## 四、Bug清单
| BugID | 接口 | 严重程度 | 问题描述 | 状态 |
|-------|-----|---------|---------|------|
| API-BUG-001 | POST /users | 高 | 创建用户时缺少username返回500而非400 | 待修复 |
| API-BUG-002 | GET /orders | 中 | 分页参数page=-1未校验 | 待修复 |
| API-BUG-003 | POST /pay | 高 | 支付金额可被篡改 | 待修复 |
| API-BUG-004 | GET /products | 低 | 排序参数未验证SQL注入 | 待修复 |
## 五、安全测试结果
| 测试项 | 结果 |
|-------|------|
| SQL注入防护 | ✅ 通过 |
| XSS防护 | ✅ 通过 |
| 未授权访问 | ❌ 发现3处越权漏洞 |
| 敏感信息泄露 | ⚠️ 返回用户ID可能被遍历 |
| HTTPS强制 | ✅ 通过 |
## 六、测试结论
✅ **建议发布** / ❌ **不建议发布** / ⚠️ **修复后发布**
**主要问题:**
1. 支付金额可被篡改(高危)
2. 存在3处越权访问漏洞(中危)
**建议:**
1. 修复高危和中危漏洞后发布
2. 增加接口签名验证
3. 增加请求频率限制
@orchestrator
后端API测试完成!
【测试概述】
测试了XX个接口,共XX个用例
【测试结果】
- 通过用例:XX个
- 失败用例:XX个
- 通过率:XX%
【性能测试】
- 平均响应时间:XXms
- 95%响应时间:XXms
- 并发能力:XX QPS
【发现的问题】
| BugID | 严重程度 | 接口 | 问题描述 |
|-------|---------|-----|---------|
| API-BUG-001 | 高 | POST /users | xxx |
【安全测试】
- SQL注入:✅通过
- 越权访问:❌发现X处问题
【测试结论】
✅ 建议发布 / ❌ 不建议发布
【完整测试报告】
[附上详细的测试文档]
老王说:后端测试不是简单的调调接口,要从业务、安全、性能多角度全面测试!一个没测好的后端上线就是给前端挖坑!
testing
AI驱动的智能浏览器自动化工具。使用LLM理解页面并自动执行任务,比传统Playwright更智能、更省token。适用于复杂交互、动态页面、需要智能决策的浏览器操作。Chrome浏览器优先。
tools
网页登录态管理。使用 fast-browser-use (fbu) 管理各平台登录状态,定期检查可用性,新平台授权时自动保存 profile。
development
Monitor and report on API provider quotas, balances, and usage. Query official providers (Moonshot, DeepSeek, xAI, Google AI Studio) and relay/proxy providers (Xingjiabiapi, Aixn, WoW) via their billing APIs. Also checks subscription services (Brave Search, OpenRouter). Generates quota reports. Triggers on "查额度", "API余额", "quota check", "billing report", "api balance", "供应商额度", "中转站余额", "费用报告", "check balance", "how much credit".
development
# A股基金监控 Skill A股基金净值监控,支持实时估值和盘后净值,自动判断交易日/节假日。 ## 用法 ### 快速监控(命令行) ```bash # 默认配置,输出到控制台 bash ~/clawd/skills/a-fund-monitor/scripts/monitor.sh # 推送到群(使用--push参数) bash ~/clawd/skills/a-fund-monitor/scripts/monitor.sh --push # 监控指定基金 bash ~/clawd/skills/a-fund-monitor/scripts/monitor.sh --codes "000979 002943" ``` ### Agent调用 ``` 执行A股基金监控任务。 1. 读取配置文件: ~/clawd/skills/a-fund-monitor/config.json 2. 获取实时净值数据 3. 非交易日自动切换为简短报告 配置文件格式: { "funds": [ {"code": "000979", "name": "景顺长城沪港深精选股票