api-testing

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

API 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.com

The Golden Rule

黄金法则

Authenticate with
As  <StateName>
FIRST, then make API calls. The browser session carries everything.
robot
As    Admin
Go To    https://app.example.com
GET    /api/users
Response Status Should Be    200
Never re-authenticate inside a test. Never manually copy tokens. The browser already has them.
首先使用
As  <StateName>
完成身份验证,再发起API调用。浏览器会话会携带所有必要的身份信息。
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-Header
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-Header

POST

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    editor
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    editor

PUT / 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.com
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.com

DELETE

DELETE

robot
DELETE    /delete
Response Status Should Be    200
robot
DELETE    /delete
Response Status Should Be    200

POST 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    alice
robot
POST Form    /post    fields={"username": "alice", "password": "secret"}
Response Status Should Be    200
Field Equals    form.username    alice

POST Multipart (file upload)

POST Multipart (文件上传)

robot
undefined
robot
undefined

File 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
undefined
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
undefined

CURL — 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-Header
Right-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
    /api/users
    — resolved against the current page origin. The browser must already be at the target site (via
    Go To
    or
    As
    ).
  • Absolute
    https://httpbin.playground.helpmetest.com/get
    — works from any page, no prior navigation needed.
  • Same-origin APIs — use relative URLs after navigating to the app; no CORS concerns.
  • Cross-origin APIs — use absolute URLs; the server must allow
    credentials: include
    CORS requests.
  • 相对路径
    /api/users
    — 基于当前页面的域名解析,浏览器必须已经通过
    Go To
    As
    指令打开了目标站点。
  • 绝对路径
    https://httpbin.playground.helpmetest.com/get
    — 可在任意页面使用,无需提前导航。
  • 同域API — 导航到应用站点后使用相对URL即可,无需担心CORS问题。
  • 跨域API — 使用绝对URL,服务端必须允许
    credentials: include
    的CORS请求。

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    500
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    500

Body text (raw string match)

响应体文本(原始字符串匹配)

robot
GET    /get
Response Body Should Contain    "url"
Response Body Should Not Contain    error
robot
GET    /get
Response Body Should Contain    "url"
Response Body Should Not Contain    error

Partial 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: |
#string
| any string (including empty) | |
#number
| any integer or float | |
#boolean
| true or false | |
#array
| any JSON array | |
#object
| any JSON object | |
#null
| JSON null | |
#notnull
| any non-null value | |
#present
| key exists (value may be null) | |
#ignore
| skip this field entirely |
检查响应是否包含预期结构,额外字段会被忽略。
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"}
类型占位符: |
#string
| 任意字符串(包括空字符串) | |
#number
| 任意整数或浮点数 | |
#boolean
| true 或 false | |
#array
| 任意JSON数组 | |
#object
| 任意JSON对象 | |
#null
| JSON null | |
#notnull
| 任意非null值 | |
#present
| 键存在(值可以为null) | |
#ignore
| 完全跳过该字段的校验 |

Field assertions (dot-path)

字段断言(点路径)

Navigate nested JSON with
.
and array indices with
.N
:
robot
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结构,使用
.N
访问数组索引:
robot
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

Field 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    object
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    object

Array 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.items
When the response root is an array, use
${EMPTY}
as the field path:
robot
undefined
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.items
当响应根节点是数组时,使用
${EMPTY}
作为字段路径:
robot
undefined

hypothetical endpoint returning a JSON array

假设该端点返回一个JSON数组

GET /json-array-endpoint Field Length Should Be ${EMPTY} 5 Field Each Should Match ${EMPTY} {"id": "#number"}
undefined
GET /json-array-endpoint Field Length Should Be ${EMPTY} 5 Field Each Should Match ${EMPTY} {"id": "#number"}
undefined

Array 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.data
robot
POST    /post    body={"errors": [], "data": [1, 2, 3]}
Field Should Be Empty    json.errors
Field Should Not Be Empty    json.data

Response headers

响应头

robot
GET    /response-headers?Content-Type=application/json
Response Header Should Be    content-type    application/json
Response Header Should Contain    content-type    json
robot
GET    /response-headers?Content-Type=application/json
Response Header Should Be    content-type    application/json
Response Header Should Contain    content-type    json

Response time

响应时间

robot
GET    /get
Response Time Should Be Less Than    2000
robot
GET    /get
Response Time Should Be Less Than    2000

httpbin /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
undefined
GET /delay/1 Response Time Should Be Less Than 3000
undefined

Extracting Values to Chain Requests

提取值用于链式请求

Get Response Field
returns a value for use in the next request — the standard pattern for dependent calls.
robot
POST    /post    body={"name": "Alice"}
Response Status Should Be    200
${name}=    Get Response Field    json.name
Get Response Field
会返回对应值用于下一个请求——这是处理依赖调用的标准模式。
robot
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    404

Error Scenarios

错误场景测试

Always test the unhappy paths:
robot
Go To    https://httpbin.playground.helpmetest.com
一定要测试非预期路径:
robot
Go To    https://httpbin.playground.helpmetest.com

404

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
undefined
As RegularUser POST /api/admin/users body={"name": "Bob"} Response Status Should Be 403
undefined

Common Pitfalls

常见陷阱

Don't use Javascript fetch in tests. The API library exists precisely so you don't have to.
Javascript    fetch(...)
bypasses auth, skips rrweb recording, and produces brittle tests.
Relative URLs require the browser to be at the site. Always pair with
As  <StateName>
+
Go To
at the top. Without navigation, the relative URL resolves against whatever origin the browser last visited.
Body is a JSON string. Pass
body={"key": "value"}
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.
httpbin echoes what you send. When testing against
httpbin.playground.helpmetest.com
, JSON body fields come back under
.json
, form fields under
.form
, files under
.files
, and query params under
.args
. So
POST /post body={"name":"Alice"}
→ assert
json.name
, not
name
.
不要在测试中使用Javascript fetch。 这个API库的存在就是为了让你不用手动写fetch。
Javascript    fetch(...)
会绕过身份验证、跳过rrweb录制,而且会生成脆弱的测试。
相对URL要求浏览器已经打开对应站点。 一定要在测试开头搭配
As  <StateName>
+
Go To
使用。如果没有提前导航,相对URL会基于浏览器上一次访问的域名解析。
请求体是JSON字符串。 直接传入
body={"key": "value"}
字面量即可,Robot Framework会原样传递。该库会自动序列化Python字典,但在测试中请始终将请求体写为JSON字符串字面量。
httpbin会回显你发送的所有内容。 当你在
httpbin.playground.helpmetest.com
上测试时,JSON请求体字段会放在
.json
下返回,表单字段放在
.form
下,文件放在
.files
下,查询参数放在
.args
下。所以
POST /post body={"name":"Alice"}
对应的断言应该是
json.name
,而不是
name