test(expiry): 完成 #32 接口集成测试资产
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
# 保质期接口集成测试报告(2026-03-04)
|
||||
|
||||
## 范围
|
||||
- 登录获取 Token(`/api/v1/auth/login`)
|
||||
- 物品接口:创建、列表、汇总、更新、状态标记、删除
|
||||
- 设置接口:获取与更新
|
||||
|
||||
## 测试资产
|
||||
- Postman Collection: `docs/expiry/tests/postman/expiry.postman_collection.json`
|
||||
- Postman Environment: `docs/expiry/tests/postman/expiry.postman_environment.json`
|
||||
- 一键脚本: `scripts/expiry/run_integration_tests.sh`
|
||||
|
||||
## 执行方式
|
||||
```bash
|
||||
# 方式一:已有 token
|
||||
BASE_URL=http://127.0.0.1:8080 TOKEN=<session_key> scripts/expiry/run_integration_tests.sh
|
||||
|
||||
# 方式二:通过 wx.login 的 code 登录
|
||||
BASE_URL=http://127.0.0.1:8080 MINI_PROGRAM_ID=1 WX_CODE=<wx_code> scripts/expiry/run_integration_tests.sh
|
||||
```
|
||||
|
||||
## 断言规则
|
||||
- 登录接口:`HTTP 200 && code == 200`
|
||||
- 业务接口:`HTTP 200 && code == 0`
|
||||
- 错误接口:预期返回 4xx/5xx 与对应 message
|
||||
|
||||
## 性能测试建议
|
||||
脚本内置 `hey` 调用(若系统已安装):
|
||||
```bash
|
||||
hey -n 100 -c 20 -H "Authorization: Bearer <token>" http://127.0.0.1:8080/api/expiry/summary
|
||||
```
|
||||
|
||||
目标:平均响应时间 < 200ms(开发环境仅作参考,生产环境需复测)。
|
||||
@@ -0,0 +1,170 @@
|
||||
{
|
||||
"info": {
|
||||
"_postman_id": "3f8f9f2a-8b2f-4cc0-91df-0c8d7a03b101",
|
||||
"name": "Expiry API Integration",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
|
||||
"description": "保质期提醒小程序后端接口集成测试集合"
|
||||
},
|
||||
"item": [
|
||||
{
|
||||
"name": "Auth - Login",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{ "key": "Content-Type", "value": "application/json" }
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"mini_program_id\": {{mini_program_id}},\n \"code\": \"{{wx_code}}\"\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{base_url}}/api/v1/auth/login",
|
||||
"host": ["{{base_url}}"],
|
||||
"path": ["api", "v1", "auth", "login"]
|
||||
}
|
||||
},
|
||||
"event": [
|
||||
{
|
||||
"listen": "test",
|
||||
"script": {
|
||||
"exec": [
|
||||
"pm.test('login status 200', function () {",
|
||||
" pm.response.to.have.status(200);",
|
||||
"});",
|
||||
"const json = pm.response.json();",
|
||||
"pm.test('login business code 200', function () {",
|
||||
" pm.expect(json.code).to.eql(200);",
|
||||
"});",
|
||||
"if (json.data && json.data.session_key) {",
|
||||
" pm.environment.set('token', json.data.session_key);",
|
||||
"}"
|
||||
],
|
||||
"type": "text/javascript"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Expiry - Create Item",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{ "key": "Content-Type", "value": "application/json" },
|
||||
{ "key": "Authorization", "value": "Bearer {{token}}" }
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"name\": \"自动化牛奶\",\n \"category\": \"food\",\n \"expiry_date\": \"2030-12-31\",\n \"quantity\": 2,\n \"location\": \"冰箱\"\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{base_url}}/api/expiry/items",
|
||||
"host": ["{{base_url}}"],
|
||||
"path": ["api", "expiry", "items"]
|
||||
}
|
||||
},
|
||||
"event": [
|
||||
{
|
||||
"listen": "test",
|
||||
"script": {
|
||||
"exec": [
|
||||
"const json = pm.response.json();",
|
||||
"pm.test('create success', function () {",
|
||||
" pm.expect(pm.response.code).to.eql(200);",
|
||||
" pm.expect(json.code).to.eql(0);",
|
||||
"});",
|
||||
"if (json.data && json.data.id) {",
|
||||
" pm.environment.set('item_id', json.data.id);",
|
||||
"}"
|
||||
],
|
||||
"type": "text/javascript"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Expiry - Get Items",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{ "key": "Authorization", "value": "Bearer {{token}}" }
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{base_url}}/api/expiry/items?status=all&page=1&page_size=20",
|
||||
"host": ["{{base_url}}"],
|
||||
"path": ["api", "expiry", "items"],
|
||||
"query": [
|
||||
{ "key": "status", "value": "all" },
|
||||
{ "key": "page", "value": "1" },
|
||||
{ "key": "page_size", "value": "20" }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Expiry - Get Summary",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{ "key": "Authorization", "value": "Bearer {{token}}" }
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{base_url}}/api/expiry/summary",
|
||||
"host": ["{{base_url}}"],
|
||||
"path": ["api", "expiry", "summary"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Expiry - Update Status Used",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{ "key": "Content-Type", "value": "application/json" },
|
||||
{ "key": "Authorization", "value": "Bearer {{token}}" }
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"status\": \"used\"\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{base_url}}/api/expiry/items/{{item_id}}/status",
|
||||
"host": ["{{base_url}}"],
|
||||
"path": ["api", "expiry", "items", "{{item_id}}", "status"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Expiry - Settings Get",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{ "key": "Authorization", "value": "Bearer {{token}}" }
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{base_url}}/api/expiry/settings",
|
||||
"host": ["{{base_url}}"],
|
||||
"path": ["api", "expiry", "settings"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Expiry - Settings Update",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{ "key": "Content-Type", "value": "application/json" },
|
||||
{ "key": "Authorization", "value": "Bearer {{token}}" }
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"remind_days\": [10, 5, 1]\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "{{base_url}}/api/expiry/settings",
|
||||
"host": ["{{base_url}}"],
|
||||
"path": ["api", "expiry", "settings"]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"id": "4f72d514-2fe4-4125-9ef0-2b5240ca07c4",
|
||||
"name": "Expiry Local Env",
|
||||
"values": [
|
||||
{ "key": "base_url", "value": "http://127.0.0.1:8080", "enabled": true },
|
||||
{ "key": "mini_program_id", "value": "1", "enabled": true },
|
||||
{ "key": "wx_code", "value": "请替换为wx.login()返回code", "enabled": true },
|
||||
{ "key": "token", "value": "", "enabled": true },
|
||||
{ "key": "item_id", "value": "", "enabled": true }
|
||||
],
|
||||
"_postman_variable_scope": "environment",
|
||||
"_postman_exported_at": "2026-03-04T18:40:00.000Z",
|
||||
"_postman_exported_using": "postman"
|
||||
}
|
||||
Executable
+97
@@ -0,0 +1,97 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
BASE_URL="${BASE_URL:-http://127.0.0.1:8080}"
|
||||
MINI_PROGRAM_ID="${MINI_PROGRAM_ID:-1}"
|
||||
WX_CODE="${WX_CODE:-}"
|
||||
TOKEN="${TOKEN:-}"
|
||||
|
||||
need_cmd() {
|
||||
command -v "$1" >/dev/null 2>&1 || {
|
||||
echo "缺少命令: $1" >&2
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
need_cmd curl
|
||||
need_cmd jq
|
||||
|
||||
echo "[1/8] 准备 token"
|
||||
if [[ -z "$TOKEN" ]]; then
|
||||
if [[ -z "$WX_CODE" ]]; then
|
||||
echo "请提供 TOKEN 或 WX_CODE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TOKEN="$(curl -sS -X POST "${BASE_URL}/api/v1/auth/login" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d "{\"mini_program_id\":${MINI_PROGRAM_ID},\"code\":\"${WX_CODE}\"}" \
|
||||
| jq -r '.data.session_key')"
|
||||
fi
|
||||
|
||||
if [[ -z "$TOKEN" || "$TOKEN" == "null" ]]; then
|
||||
echo "获取 token 失败" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
auth_header=( -H "Authorization: Bearer ${TOKEN}" )
|
||||
|
||||
assert_code_zero() {
|
||||
local payload="$1"
|
||||
local api_code
|
||||
api_code="$(echo "$payload" | jq -r '.code')"
|
||||
if [[ "$api_code" != "0" ]]; then
|
||||
echo "接口业务码异常: ${api_code}, payload=${payload}" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
echo "[2/8] 创建物品"
|
||||
create_payload="$(curl -sS -X POST "${BASE_URL}/api/expiry/items" \
|
||||
"${auth_header[@]}" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"name":"集成测试牛奶","category":"food","expiry_date":"2030-12-31","quantity":2,"location":"冰箱"}')"
|
||||
assert_code_zero "$create_payload"
|
||||
item_id="$(echo "$create_payload" | jq -r '.data.id')"
|
||||
|
||||
echo "[3/8] 查询列表"
|
||||
list_payload="$(curl -sS "${BASE_URL}/api/expiry/items?status=all&page=1&page_size=20" "${auth_header[@]}")"
|
||||
assert_code_zero "$list_payload"
|
||||
|
||||
echo "[4/8] 查询汇总"
|
||||
summary_payload="$(curl -sS "${BASE_URL}/api/expiry/summary" "${auth_header[@]}")"
|
||||
assert_code_zero "$summary_payload"
|
||||
|
||||
echo "[5/8] 更新物品"
|
||||
update_payload="$(curl -sS -X PUT "${BASE_URL}/api/expiry/items/${item_id}" \
|
||||
"${auth_header[@]}" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"name":"集成测试牛奶(更新)","category":"food","expiry_date":"2030-12-30","quantity":1}')"
|
||||
assert_code_zero "$update_payload"
|
||||
|
||||
echo "[6/8] 标记已使用"
|
||||
status_payload="$(curl -sS -X POST "${BASE_URL}/api/expiry/items/${item_id}/status" \
|
||||
"${auth_header[@]}" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"status":"used"}')"
|
||||
assert_code_zero "$status_payload"
|
||||
|
||||
echo "[7/8] 设置提醒"
|
||||
settings_payload="$(curl -sS -X POST "${BASE_URL}/api/expiry/settings" \
|
||||
"${auth_header[@]}" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d '{"remind_days":[10,5,1]}')"
|
||||
assert_code_zero "$settings_payload"
|
||||
|
||||
echo "[8/8] 删除物品"
|
||||
delete_payload="$(curl -sS -X DELETE "${BASE_URL}/api/expiry/items/${item_id}" "${auth_header[@]}")"
|
||||
assert_code_zero "$delete_payload"
|
||||
|
||||
echo "全部接口集成测试通过"
|
||||
|
||||
if command -v hey >/dev/null 2>&1; then
|
||||
echo "开始性能测试: /api/expiry/summary 并发 20,总请求 100"
|
||||
hey -n 100 -c 20 -H "Authorization: Bearer ${TOKEN}" "${BASE_URL}/api/expiry/summary"
|
||||
else
|
||||
echo "未安装 hey,跳过性能测试(建议安装后执行:hey -n 100 -c 20 ${BASE_URL}/api/expiry/summary)"
|
||||
fi
|
||||
Reference in New Issue
Block a user