API测试 api-testing

API测试技能用于通过Supertest(TypeScript/JavaScript)和httpx/pytest(Python)工具测试HTTP API。支持REST API、GraphQL、请求/响应验证、认证、错误处理和性能测试,帮助确保API的可靠性、安全性和性能。关键词:API测试,HTTP API,REST API,GraphQL,Supertest,httpx,pytest,TypeScript,Python,自动化测试。

测试 0 次安装 0 次浏览 更新于 3/8/2026

name: api-testing description: TypeScript(Supertest)和Python(httpx, pytest)的HTTP API测试。测试REST API、GraphQL、请求/响应验证、认证和错误处理。 allowed-tools: Bash, Read, Edit, Write, Grep, Glob, TodoWrite

API测试

使用Supertest(TypeScript/JavaScript)和httpx/pytest(Python)测试HTTP API的专业知识。

TypeScript/JavaScript(Supertest)

安装

# 使用Bun
bun add -d supertest @types/supertest

# 或:npm install -D supertest @types/supertest

基础设置

import { describe, it, expect } from 'vitest'
import request from 'supertest'
import { app } from './app'

describe('API测试', () => {
  it('返回健康状态', async () => {
    const response = await request(app)
      .get('/api/health')
      .expect(200)

    expect(response.body).toEqual({ status: 'ok' })
  })

  it('创建用户', async () => {
    const response = await request(app)
      .post('/api/users')
      .send({ name: 'John Doe', email: 'john@example.com' })
      .expect(201)

    expect(response.body).toMatchObject({
      id: expect.any(Number),
      name: 'John Doe',
    })
  })

  it('验证必填字段', async () => {
    await request(app)
      .post('/api/users')
      .send({ name: 'John Doe' })
      .expect(400)
  })
})

请求方法

// GET
await request(app).get('/api/users').expect(200)

// POST带请求体
await request(app)
  .post('/api/users')
  .send({ name: 'John' })
  .expect(201)

// PUT
await request(app)
  .put('/api/users/1')
  .send({ name: 'Jane' })
  .expect(200)

// DELETE
await request(app).delete('/api/users/1').expect(204)

头部和查询参数

// 设置头部
await request(app)
  .get('/api/protected')
  .set('Authorization', 'Bearer token123')
  .expect(200)

// 查询参数
await request(app)
  .get('/api/users')
  .query({ page: 1, limit: 10 })
  .expect(200)

认证测试

describe('认证', () => {
  let authToken: string

  beforeAll(async () => {
    const response = await request(app)
      .post('/api/auth/login')
      .send({ email: 'user@example.com', password: 'password123' })
      .expect(200)

    authToken = response.body.token
  })

  it('访问受保护端点', async () => {
    await request(app)
      .get('/api/protected')
      .set('Authorization', `Bearer ${authToken}`)
      .expect(200)
  })

  it('拒绝无令牌访问', async () => {
    await request(app).get('/api/protected').expect(401)
  })
})

错误处理

it('处理验证错误', async () => {
  const response = await request(app)
    .post('/api/users')
    .send({ email: 'invalid-email' })
    .expect(400)

  expect(response.body).toMatchObject({
    error: '验证失败',
    details: expect.any(Array),
  })
})

it('处理未找到', async () => {
  await request(app).get('/api/users/999999').expect(404)
})

Python(httpx + pytest)

安装

uv add --dev httpx pytest-asyncio

基础设置

import pytest
from fastapi.testclient import TestClient
from main import app

client = TestClient(app)

def test_health_check():
    response = client.get("/api/health")
    assert response.status_code == 200
    assert response.json() == {"status": "ok"}

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

def test_not_found():
    response = client.get("/api/users/999")
    assert response.status_code == 404

固件

@pytest.fixture
def auth_token(client):
    response = client.post(
        "/api/auth/login",
        json={"email": "user@example.com", "password": "password123"}
    )
    return response.json()["token"]

def test_protected_endpoint(client, auth_token):
    response = client.get(
        "/api/protected",
        headers={"Authorization": f"Bearer {auth_token}"}
    )
    assert response.status_code == 200

文件上传

def test_file_upload(client, tmp_path):
    test_file = tmp_path / "test.txt"
    test_file.write_text("测试内容")

    with open(test_file, "rb") as f:
        response = client.post(
            "/api/upload",
            files={"file": ("test.txt", f, "text/plain")}
        )

    assert response.status_code == 200

GraphQL测试

it('查询GraphQL端点', async () => {
  const query = `
    query GetUser($id: ID!) {
      user(id: $id) { id name email }
    }
  `

  const response = await request(app)
    .post('/graphql')
    .send({ query, variables: { id: '1' } })
    .expect(200)

  expect(response.body.data.user).toMatchObject({
    id: '1',
    name: expect.any(String),
  })
})

性能测试

it('在可接受时间内响应', async () => {
  const start = Date.now()
  await request(app).get('/api/users').expect(200)
  const duration = Date.now() - start
  expect(duration).toBeLessThan(100) // 100毫秒阈值
})

最佳实践

  • describe块中分组相关端点
  • 在测试间重置数据库
  • 首先验证状态码
  • 检查响应结构
  • 测试错误消息格式
  • 模拟外部服务
  • 测试正常路径和错误案例

另请参阅

  • vitest-testing - 单元测试框架
  • playwright-testing - 端到端API测试
  • test-quality-analysis - 测试质量模式