前置知识: 软件测试

API自动化测试

2 minIntermediate2026/6/14

API自动化测试:RESTful API测试、工具选型、断言策略与框架设计详解。

1. API 测试概述

1.1 什么是 API 测试

API 测试是在没有用户界面的情况下,直接对应用程序编程接口进行测试,验证接口的功能、性能和安全性。

1.2 与 UI 测试对比

对比项API 测试UI 测试
速度快(毫秒)慢(秒)
稳定性
覆盖率
维护成本
反馈速度

1.3 测试层级

契约测试 → 功能测试 → 集成测试 → 端到端测试

2. 工具选型

工具语言特点
PostmanGUI易上手、Collection
REST AssuredJava强大、灵活
Requests + pytestPython轻量、灵活
SuperTestNode.jsJS 生态
KarateDSLBDD 风格
HttpRunnerPython中文友好

3. Python API 测试框架

3.1 基础封装

import requests

class APIClient:
    def __init__(self, base_url):
        self.base_url = base_url
        self.session = requests.Session()
        self.token = None

    def set_token(self, token):
        self.token = token
        self.session.headers.update({"Authorization": f"Bearer {token}"})

    def get(self, path, **kwargs):
        return self.session.get(f"{self.base_url}{path}", **kwargs)

    def post(self, path, json=None, **kwargs):
        return self.session.post(f"{self.base_url}{path}", json=json, **kwargs)

    def put(self, path, json=None, **kwargs):
        return self.session.put(f"{self.base_url}{path}", json=json, **kwargs)

    def delete(self, path, **kwargs):
        return self.session.delete(f"{self.base_url}{path}", **kwargs)

3.2 测试用例

import pytest

@pytest.fixture
def api():
    client = APIClient("https://api.example.com")
    # 登录获取 Token
    response = client.post("/auth/login", json={
        "username": "admin",
        "password": "password123"
    })
    client.set_token(response.json()["token"])
    return client

class TestUserAPI:

    def test_create_user(self, api):
        response = api.post("/api/users", json={
            "name": "Alice",
            "email": "alice@example.com"
        })
        assert response.status_code == 201
        data = response.json()
        assert data["name"] == "Alice"
        assert "id" in data

    def test_get_user(self, api):
        # 先创建
        create_resp = api.post("/api/users", json={
            "name": "Bob", "email": "bob@example.com"
        })
        user_id = create_resp.json()["id"]

        # 再查询
        response = api.get(f"/api/users/{user_id}")
        assert response.status_code == 200
        assert response.json()["name"] == "Bob"

    def test_update_user(self, api):
        create_resp = api.post("/api/users", json={
            "name": "Charlie", "email": "charlie@example.com"
        })
        user_id = create_resp.json()["id"]

        response = api.put(f"/api/users/{user_id}", json={
            "name": "Charlie Updated"
        })
        assert response.status_code == 200
        assert response.json()["name"] == "Charlie Updated"

    def test_delete_user(self, api):
        create_resp = api.post("/api/users", json={
            "name": "David", "email": "david@example.com"
        })
        user_id = create_resp.json()["id"]

        response = api.delete(f"/api/users/{user_id}")
        assert response.status_code == 204

        # 验证已删除
        get_resp = api.get(f"/api/users/{user_id}")
        assert get_resp.status_code == 404

4. 断言策略

4.1 状态码断言

assert response.status_code == 200
assert response.status_code in [200, 201]

4.2 响应体断言

# JSON Schema 验证
from jsonschema import validate

schema = {
    "type": "object",
    "required": ["id", "name", "email"],
    "properties": {
        "id": {"type": "integer"},
        "name": {"type": "string"},
        "email": {"type": "string", "format": "email"}
    }
}

validate(instance=response.json(), schema=schema)

4.3 响应时间断言

assert response.elapsed.total_seconds() < 2.0

4.4 响应头断言

assert "application/json" in response.headers["Content-Type"]
assert "X-Request-Id" in response.headers

5. 数据驱动测试

5.1 YAML 数据文件

# testdata/users.yaml
create_user:
  - name: 'Alice'
    email: 'alice@example.com'
    expected_status: 201
  - name: ''
    email: 'invalid'
    expected_status: 400
  - name: 'Bob'
    email: ''
    expected_status: 400

5.2 参数化测试

import yaml

@pytest.fixture
def user_test_data():
    with open("testdata/users.yaml") as f:
        return yaml.safe_load(f)["create_user"]

@pytest.mark.parametrize("data", user_test_data(), ids=lambda d: d["name"])
def test_create_user_data_driven(api, data):
    response = api.post("/api/users", json={
        "name": data["name"],
        "email": data["email"]
    })
    assert response.status_code == data["expected_status"]

6. 契约测试

6.1 Pact 框架

from pact import Consumer, Provider

pact = Consumer('WebApp').has_pact_with(Provider('API'))

(pact
 .given('user exists')
 .upon_receiving('a request for user')
 .with_request('GET', '/api/users/1')
 .will_respond_with(200, body={
     'id': 1,
     'name': 'Alice'
 }))

with pact:
    result = api.get('/api/users/1')
    assert result.json()['name'] == 'Alice'

7. 最佳实践

实践描述
分层封装Client → Service → Test
数据工厂自动创建测试数据
清理数据测试后清理
环境隔离测试环境独立
幂等设计重复执行结果一致
并发安全测试间无依赖
日志记录请求/响应完整记录