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/claude-code-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
通用自媒体文章自动发布工具。支持百家号、搜狐号、知乎、微信公众号、小红书、抖音号六个平台的自动化发布流程。使用Playwright自动化实现平台导航和发布,支持通过storageState管理Cookie实现账号切换。
development
# SKILL.md - Model Configuration Status (mcstatus) ## 触发条件 - `/mcstatus` 命令 - 用户询问模型配备、模型配置、model status、模型列表等 ## 功能 实时生成 Agent + Cron 的模型配置报告,展示当前所有 agent 的主模型/fallback链和所有 cron 任务的模型分配。 ## 执行步骤 ### Step 1: 收集 Agent 模型配置 读取各 agent 的 models.json 获取主模型和 fallback 链: ```bash for agent in main ops code quant data research content market finance pm law product sales batch; do config=$(cat ~/.openclaw/agents/$agent/agent/models.json 2>/dev/null) if [ -n "$config" ]; then echo "=== $agent
tools
MCP 服务器智能管理助手。自动检测 MCP 可用性、智能开关、功能问答,提供人性化的 MCP 管理体验。
tools
从GitHub搜索并自动安装配置MCP(Model Context Protocol)服务器工具到Claude配置文件。当用户需要安装MCP工具时触发此技能。工作流程:搜索GitHub上的MCP项目 -> 提取npx配置 -> 添加到~/.claude.json -> 处理API密钥(如有)。