api-testing
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAPI Testing with HelpMeTest
使用HelpMeTest进行API测试
The API library runs HTTP requests inside the active browser tab. This means the browser's session cookies, auth headers, and credentials are sent automatically — no token juggling.
A live httpbin instance is available for examples and exploration:
https://httpbin.playground.helpmetest.com该API库在当前活跃的浏览器标签页内运行HTTP请求。这意味着浏览器的会话cookie、身份验证头和凭证会自动发送——无需手动处理token。
你可以使用以下公开的httpbin实例进行示例测试和探索:
https://httpbin.playground.helpmetest.comThe Golden Rule
黄金法则
Authenticate with FIRST, then make API calls. The browser session carries everything.
As <StateName>robot
As Admin
Go To https://app.example.com
GET /api/users
Response Status Should Be 200Never re-authenticate inside a test. Never manually copy tokens. The browser already has them.
首先使用完成身份验证,再发起API调用。浏览器会话会携带所有必要的身份信息。
As <StateName>robot
As Admin
Go To https://app.example.com
GET /api/users
Response Status Should Be 200永远不要在测试内重复进行身份验证,永远不要手动复制token,浏览器已经持有这些信息。
HTTP Verbs
HTTP请求动词
GET
GET
robot
Go To https://httpbin.playground.helpmetest.com
GET /get
Response Status Should Be 200
Field Should Exist url
GET /get headers={"X-Custom-Header": "hello"}
Field Should Exist headers.X-Custom-Headerrobot
Go To https://httpbin.playground.helpmetest.com
GET /get
Response Status Should Be 200
Field Should Exist url
GET /get headers={"X-Custom-Header": "hello"}
Field Should Exist headers.X-Custom-HeaderPOST
POST
robot
Go To https://httpbin.playground.helpmetest.com
POST /post body={"name": "Alice", "role": "editor"}
Response Status Should Be 200
Field Equals json.name Alice
Field Equals json.role editorrobot
Go To https://httpbin.playground.helpmetest.com
POST /post body={"name": "Alice", "role": "editor"}
Response Status Should Be 200
Field Equals json.name Alice
Field Equals json.role editorPUT / PATCH
PUT / PATCH
robot
PUT /put body={"name": "Alice Updated"}
Response Status Should Be 200
Field Equals json.name Alice Updated
PATCH /patch body={"email": "new@example.com"}
Response Status Should Be 200
Field Equals json.email new@example.comrobot
PUT /put body={"name": "Alice Updated"}
Response Status Should Be 200
Field Equals json.name Alice Updated
PATCH /patch body={"email": "new@example.com"}
Response Status Should Be 200
Field Equals json.email new@example.comDELETE
DELETE
robot
DELETE /delete
Response Status Should Be 200robot
DELETE /delete
Response Status Should Be 200POST Form (application/x-www-form-urlencoded)
POST Form (application/x-www-form-urlencoded)
robot
POST Form /post fields={"username": "alice", "password": "secret"}
Response Status Should Be 200
Field Equals form.username alicerobot
POST Form /post fields={"username": "alice", "password": "secret"}
Response Status Should Be 200
Field Equals form.username alicePOST Multipart (file upload)
POST Multipart (文件上传)
robot
undefinedrobot
undefinedFile on disk
磁盘上的文件
POST Multipart /post files={"avatar": "/tmp/photo.png"}
Response Status Should Be 200
POST Multipart /post files={"avatar": "/tmp/photo.png"}
Response Status Should Be 200
Inline base64 — no file on disk needed
内联base64内容——无需在磁盘上存储文件
POST Multipart /post
... fields={"title": "Report"}
... files={"file": {"base64": "SGVsbG8gV29ybGQ=", "filename": "hello.txt", "content_type": "text/plain"}}
Response Status Should Be 200
Field Should Exist files.file
undefinedPOST Multipart /post
... fields={"title": "Report"}
... files={"file": {"base64": "SGVsbG8gV29ybGQ=", "filename": "hello.txt", "content_type": "text/plain"}}
Response Status Should Be 200
Field Should Exist files.file
undefinedCURL — paste directly from DevTools
CURL — 直接粘贴从DevTools复制的内容
robot
CURL curl 'https://httpbin.playground.helpmetest.com/get' -H 'X-My-Header: test'
Response Status Should Be 200
Field Should Exist headers.X-My-HeaderRight-click any network request in DevTools → "Copy as cURL" → paste. The library replaces the cookies in the copied command with the live browser session automatically.
robot
CURL curl 'https://httpbin.playground.helpmetest.com/get' -H 'X-My-Header: test'
Response Status Should Be 200
Field Should Exist headers.X-My-Header右键点击DevTools中的任意网络请求→「复制为cURL」→粘贴即可。该库会自动将复制命令中的cookie替换为当前浏览器会话的实时cookie。
URL Rules
URL规则
- Relative — resolved against the current page origin. The browser must already be at the target site (via
/api/usersorGo To).As - Absolute — works from any page, no prior navigation needed.
https://httpbin.playground.helpmetest.com/get - Same-origin APIs — use relative URLs after navigating to the app; no CORS concerns.
- Cross-origin APIs — use absolute URLs; the server must allow CORS requests.
credentials: include
- 相对路径 — 基于当前页面的域名解析,浏览器必须已经通过
/api/users或Go To指令打开了目标站点。As - 绝对路径 — 可在任意页面使用,无需提前导航。
https://httpbin.playground.helpmetest.com/get - 同域API — 导航到应用站点后使用相对URL即可,无需担心CORS问题。
- 跨域API — 使用绝对URL,服务端必须允许的CORS请求。
credentials: include
Asserting the Response
响应断言
Status
状态码
robot
Go To https://httpbin.playground.helpmetest.com
GET /status/200
Response Status Should Be 200
GET /status/404
Response Status Should Be 404
GET /status/500
Response Status Should Be 500robot
Go To https://httpbin.playground.helpmetest.com
GET /status/200
Response Status Should Be 200
GET /status/404
Response Status Should Be 404
GET /status/500
Response Status Should Be 500Body text (raw string match)
响应体文本(原始字符串匹配)
robot
GET /get
Response Body Should Contain "url"
Response Body Should Not Contain errorrobot
GET /get
Response Body Should Contain "url"
Response Body Should Not Contain errorPartial object match (Karate-style)
部分对象匹配(Karate风格)
Checks that the response contains the expected structure. Extra fields are ignored.
robot
GET /get
Response Body Should Match {"url": "#string", "headers": "#object"}
POST /post body={"name": "Alice"}
Response Body Should Match {"json": {"name": "Alice"}, "url": "#string"}Type placeholders:
| | any string (including empty) |
| | any integer or float |
| | true or false |
| | any JSON array |
| | any JSON object |
| | JSON null |
| | any non-null value |
| | key exists (value may be null) |
| | skip this field entirely |
#string#number#boolean#array#object#null#notnull#present#ignore检查响应是否包含预期结构,额外字段会被忽略。
robot
GET /get
Response Body Should Match {"url": "#string", "headers": "#object"}
POST /post body={"name": "Alice"}
Response Body Should Match {"json": {"name": "Alice"}, "url": "#string"}类型占位符:
| | 任意字符串(包括空字符串) |
| | 任意整数或浮点数 |
| | true 或 false |
| | 任意JSON数组 |
| | 任意JSON对象 |
| | JSON null |
| | 任意非null值 |
| | 键存在(值可以为null) |
| | 完全跳过该字段的校验 |
#string#number#boolean#array#object#null#notnull#present#ignoreField assertions (dot-path)
字段断言(点路径)
Navigate nested JSON with and array indices with :
..Nrobot
GET /get headers={"X-App": "myapp"}
Field Equals headers.X-App myapp
Field Should Exist headers.Host
Field Should Not Exist headers.X-Nonexistent
POST /post body={"score": 42, "tags": ["a", "b", "c"]}
Field Equals json.score 42
Field Equals json.tags.0 a
Field Equals json.tags.2 c
Field Greater Than json.score 0
Field Less Than json.score 100
Field Greater Or Equal json.score 42
Field Less Or Equal json.score 42
POST /post body={"message": "hello world"}
Field Contains json.message hello
Field Not Contains json.message error
Field Starts With json.message hello
Field Ends With json.message world
POST /post body={"uuid": "abc-123-def"}
Field Matches Regexp json.uuid ^[a-z]+-\\d+-[a-z]+$
POST /post body={"status": "active"}
Field Should Be One Of json.status active,pending,inactive使用导航嵌套JSON结构,使用访问数组索引:
..Nrobot
GET /get headers={"X-App": "myapp"}
Field Equals headers.X-App myapp
Field Should Exist headers.Host
Field Should Not Exist headers.X-Nonexistent
POST /post body={"score": 42, "tags": ["a", "b", "c"]}
Field Equals json.score 42
Field Equals json.tags.0 a
Field Equals json.tags.2 c
Field Greater Than json.score 0
Field Less Than json.score 100
Field Greater Or Equal json.score 42
Field Less Or Equal json.score 42
POST /post body={"message": "hello world"}
Field Contains json.message hello
Field Not Contains json.message error
Field Starts With json.message hello
Field Ends With json.message world
POST /post body={"uuid": "abc-123-def"}
Field Matches Regexp json.uuid ^[a-z]+-\\d+-[a-z]+$
POST /post body={"status": "active"}
Field Should Be One Of json.status active,pending,inactiveField type checks
字段类型检查
robot
POST /post body={"name": "Alice", "score": 99, "active": true, "tags": [], "meta": {}}
Field Type Should Be json.name string
Field Type Should Be json.score number
Field Type Should Be json.active boolean
Field Type Should Be json.tags array
Field Type Should Be json.meta objectrobot
POST /post body={"name": "Alice", "score": 99, "active": true, "tags": [], "meta": {}}
Field Type Should Be json.name string
Field Type Should Be json.score number
Field Type Should Be json.active boolean
Field Type Should Be json.tags array
Field Type Should Be json.meta objectArray and string length
数组和字符串长度
robot
POST /post body={"tags": ["a", "b", "c"]}
Field Length Should Be json.tags 3
POST /post body={"items": []}
Field Should Be Empty json.items
POST /post body={"items": [1, 2]}
Field Should Not Be Empty json.itemsWhen the response root is an array, use as the field path:
${EMPTY}robot
undefinedrobot
POST /post body={"tags": ["a", "b", "c"]}
Field Length Should Be json.tags 3
POST /post body={"items": []}
Field Should Be Empty json.items
POST /post body={"items": [1, 2]}
Field Should Not Be Empty json.items当响应根节点是数组时,使用作为字段路径:
${EMPTY}robot
undefinedhypothetical endpoint returning a JSON array
假设该端点返回一个JSON数组
GET /json-array-endpoint
Field Length Should Be ${EMPTY} 5
Field Each Should Match ${EMPTY} {"id": "#number"}
undefinedGET /json-array-endpoint
Field Length Should Be ${EMPTY} 5
Field Each Should Match ${EMPTY} {"id": "#number"}
undefinedArray item matching
数组项匹配
Assert every item in an array matches a pattern:
robot
POST /post body={"users": [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]}
Field Each Should Match json.users {"id": "#number", "name": "#string"}断言数组中的每一项都匹配指定模式:
robot
POST /post body={"users": [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]}
Field Each Should Match json.users {"id": "#number", "name": "#string"}Empty / not empty
空/非空判断
robot
POST /post body={"errors": [], "data": [1, 2, 3]}
Field Should Be Empty json.errors
Field Should Not Be Empty json.datarobot
POST /post body={"errors": [], "data": [1, 2, 3]}
Field Should Be Empty json.errors
Field Should Not Be Empty json.dataResponse headers
响应头
robot
GET /response-headers?Content-Type=application/json
Response Header Should Be content-type application/json
Response Header Should Contain content-type jsonrobot
GET /response-headers?Content-Type=application/json
Response Header Should Be content-type application/json
Response Header Should Contain content-type jsonResponse time
响应时间
robot
GET /get
Response Time Should Be Less Than 2000robot
GET /get
Response Time Should Be Less Than 2000httpbin /delay/N endpoint adds N seconds — use to test timeout thresholds
httpbin的/delay/N端点会增加N秒延迟——可用于测试超时阈值
GET /delay/1
Response Time Should Be Less Than 3000
undefinedGET /delay/1
Response Time Should Be Less Than 3000
undefinedExtracting Values to Chain Requests
提取值用于链式请求
Get Response Fieldrobot
POST /post body={"name": "Alice"}
Response Status Should Be 200
${name}= Get Response Field json.nameGet Response Fieldrobot
POST /post body={"name": "Alice"}
Response Status Should Be 200
${name}= Get Response Field json.name${name} == "Alice"
${name} == "Alice"
GET /get headers={"X-Echo": "${name}"}
Field Equals headers.X-Echo Alice
```robot
${status}= Get Response Status
${body}= Get Response Body
Log ${body}GET /get headers={"X-Echo": "${name}"}
Field Equals headers.X-Echo Alice
```robot
${status}= Get Response Status
${body}= Get Response Body
Log ${body}Standard CRUD Pattern
标准CRUD测试模式
The typical shape for testing any CRUD resource:
robot
*** Test Cases ***
Create Read Update Delete User
As Admin
Go To https://app.example.com
# Create
POST /api/users body={"name": "Alice", "role": "editor"}
Response Status Should Be 201
${id}= Get Response Field id
# Read
GET /api/users/${id}
Field Equals name Alice
Field Equals role editor
# Update
PATCH /api/users/${id} body={"name": "Alice Updated"}
Response Status Should Be 200
Field Equals name Alice Updated
# Delete
DELETE /api/users/${id}
Response Status Should Be 204
# Verify gone
GET /api/users/${id}
Response Status Should Be 404测试任意CRUD资源的典型结构:
robot
*** Test Cases ***
Create Read Update Delete User
As Admin
Go To https://app.example.com
# 创建
POST /api/users body={"name": "Alice", "role": "editor"}
Response Status Should Be 201
${id}= Get Response Field id
# 读取
GET /api/users/${id}
Field Equals name Alice
Field Equals role editor
# 更新
PATCH /api/users/${id} body={"name": "Alice Updated"}
Response Status Should Be 200
Field Equals name Alice Updated
# 删除
DELETE /api/users/${id}
Response Status Should Be 204
# 验证已删除
GET /api/users/${id}
Response Status Should Be 404Error Scenarios
错误场景测试
Always test the unhappy paths:
robot
Go To https://httpbin.playground.helpmetest.com一定要测试非预期路径:
robot
Go To https://httpbin.playground.helpmetest.com404
404
GET /status/404
Response Status Should Be 404
GET /status/404
Response Status Should Be 404
500
500
GET /status/500
Response Status Should Be 500
GET /status/500
Response Status Should Be 500
App-level: missing required field
应用级别错误:缺少必填字段
As Admin
Go To https://app.example.com
POST /api/users body={"role": "editor"}
Response Status Should Be 400
Field Should Exist error
As Admin
Go To https://app.example.com
POST /api/users body={"role": "editor"}
Response Status Should Be 400
Field Should Exist error
Unauthorized (no session)
未授权(无会话)
GET /api/admin/secrets
Response Status Should Be 401
GET /api/admin/secrets
Response Status Should Be 401
Forbidden (wrong role)
禁止访问(权限不足)
As RegularUser
POST /api/admin/users body={"name": "Bob"}
Response Status Should Be 403
undefinedAs RegularUser
POST /api/admin/users body={"name": "Bob"}
Response Status Should Be 403
undefinedCommon Pitfalls
常见陷阱
Don't use Javascript fetch in tests. The API library exists precisely so you don't have to. bypasses auth, skips rrweb recording, and produces brittle tests.
Javascript fetch(...)Relative URLs require the browser to be at the site. Always pair with + at the top. Without navigation, the relative URL resolves against whatever origin the browser last visited.
As <StateName>Go ToBody is a JSON string. Pass as a literal — Robot Framework passes it through as-is. The library serializes Python dicts automatically, but always write the body as a JSON string literal in tests.
body={"key": "value"}httpbin echoes what you send. When testing against , JSON body fields come back under , form fields under , files under , and query params under . So → assert , not .
httpbin.playground.helpmetest.com.json.form.files.argsPOST /post body={"name":"Alice"}json.namename不要在测试中使用Javascript fetch。 这个API库的存在就是为了让你不用手动写fetch。会绕过身份验证、跳过rrweb录制,而且会生成脆弱的测试。
Javascript fetch(...)相对URL要求浏览器已经打开对应站点。 一定要在测试开头搭配 + 使用。如果没有提前导航,相对URL会基于浏览器上一次访问的域名解析。
As <StateName>Go To请求体是JSON字符串。 直接传入字面量即可,Robot Framework会原样传递。该库会自动序列化Python字典,但在测试中请始终将请求体写为JSON字符串字面量。
body={"key": "value"}httpbin会回显你发送的所有内容。 当你在上测试时,JSON请求体字段会放在下返回,表单字段放在下,文件放在下,查询参数放在下。所以对应的断言应该是,而不是。
httpbin.playground.helpmetest.com.json.form.files.argsPOST /post body={"name":"Alice"}json.namename