mcpField
S
setup-sdk-testing

setup-sdk-testing

github.com/speakeasy-api测试与质量1894 次安装37 周前更新
代码仓库

关于 setup-sdk-testing

用于配置和运行 Speakeasy 生成的 SDK 测试,适合验证生成的客户端是否符合 API 规范或实际 API。涵盖自动生成的契约测试、自定义 Arazzo 工作流和集成测试。

主要功能

  1. 01根据 OpenAPI 规范生成契约测试
  2. 02使用 Arazzo 定义多步骤测试
  3. 03通过 Speakeasy CLI 运行测试
  4. 04配置实时 API 集成测试
  5. 05在 GitHub Actions 中运行契约测试

适用场景

  1. 01检查 SDK 请求和响应处理是否符合规范
  2. 02测试多步骤 API 工作流
  3. 03针对测试 API 验证 SDK 行为
  4. 04SDK 重新生成后运行回归测试

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/speakeasy-api/sdk-generation-skills --skill setup-sdk-testing

安装后在 Claude Code 中输入/setup-sdk-testing确认已加载。

附带文件content/arazzo-reference.md

详细介绍

setup-sdk-testing

使用契约测试、自定义 Arazzo 工作流或针对实时 API 的集成测试,为 Speakeasy 生成的 SDK 配置并运行测试。

内容指南

主题指南
Arazzo 参考content/arazzo-reference.md

Arazzo 参考提供了工作流、步骤、成功标准、环境变量和链接操作的完整语法。

适用场景

  • 为生成的 SDK 配置自动化测试
  • 通过 gen.yaml 启用契约测试生成
  • 使用 Arazzo 编写自定义多步骤 API 工作流测试
  • 配置针对实时 API 的集成测试
  • 调试 ResponseValidationError 或测试失败
  • 用户提到:“测试 SDK”“契约测试”“Arazzo 测试”“speakeasy test”“模拟服务器”“测试生成”

输入

输入必需说明
gen.yaml是生成配置;在此处启用契约测试
OpenAPI 规范是生成 SDK 所依据的 API 规范
目标语言是typescript、python、go 或 java(支持契约测试)
.speakeasy/tests.arazzo.yaml否自定义 Arazzo 测试定义
实时 API 凭据否仅集成测试需要

输出

输出位置
生成的契约测试SDK 输出目录中的 tests/ 目录
模拟服务器配置与契约测试一起自动生成
Arazzo 测试结果speakeasy test 的终端输出
CI 工作流.github/workflows/(如果配置了集成测试)

前提条件

  • 已安装并完成身份验证的 Speakeasy CLI(speakeasy auth login)
  • 可正常运行的 SDK 生成配置(gen.yaml + OpenAPI 规范)
  • 对于集成测试:将 API 凭据设为环境变量

决策框架

根据需求选择合适的测试方法:

需求方法工作量
验证 SDK 类型和方法是否符合 API 契约契约测试低(自动生成)
测试多步骤 API 工作流(创建后再验证)自定义 Arazzo 测试中
使用真实数据针对实时 API 进行验证集成测试高
在每次重新生成 SDK 时捕获回归问题契约测试 + CI低
端到端测试身份验证流程集成测试高
验证具有数据依赖关系的链式操作自定义 Arazzo 测试中

从契约测试开始。 它会自动生成,并能捕获最常见的问题。添加自定义 Arazzo 测试以覆盖工作流;只有在需要验证实时 API 时才添加集成测试。

命令

启用契约测试

添加到 gen.yaml:

generation:
  tests:
    generateTests: true

然后重新生成 SDK:

speakeasy run --output console
运行测试
# Run all Arazzo-defined tests (contract + custom)
speakeasy test

# Run tests for a specific target
speakeasy test --target my-typescript-sdk

# Run with verbose output for debugging
speakeasy test --verbose
通过 CI 运行

启用测试生成后,契约测试会在 Speakeasy GitHub Actions 工作流中自动运行。契约测试无需额外配置 CI。

示例

1. 契约测试(快速开始)

在 gen.yaml 中启用测试生成:

generation:
  tests:
    generateTests: true

重新生成 SDK:

speakeasy run --output console

运行生成的测试:

speakeasy test

CLI 会根据 OpenAPI 规范生成测试,创建一个返回符合规范响应的模拟服务器,并验证 SDK 是否能正确处理请求和响应。

2. 自定义 Arazzo 测试

创建或编辑 .speakeasy/tests.arazzo.yaml:

arazzo: 1.0.0
info:
  title: Custom SDK Tests
  version: 1.0.0

sourceDescriptions:
  - name: my-api
    type: openapi
    url: ./openapi.yaml

workflows:
  - workflowId: create-and-verify-resource
    steps:
      - stepId: create-resource
        operationId: createResource
        requestBody:
          payload:
            name: "test-resource"
            type: "example"
        successCriteria:
          - condition: $statusCode == 201
        outputs:
          resourceId: $response.body#/id

      - stepId: get-resource
        operationId: getResource
        parameters:
          - name: id
            in: path
            value: $steps.create-resource.outputs.resourceId
        successCriteria:
          - condition: $statusCode == 200
          - condition: $response.body#/name == "test-resource"

  - workflowId: list-and-filter
    steps:
      - stepId: list-resources
        operationId: listResources
        parameters:
          - name: limit
            in: query
            value: 10
        successCriteria:
          - condition: $statusCode == 200

运行自定义测试:

speakeasy test
在 Arazzo 测试中使用环境变量

通过环境变量引用敏感值:

steps:
  - stepId: authenticated-request
    operationId: getProtectedResource
    parameters:
      - name: Authorization
        in: header
        value: Bearer $env.API_TOKEN
    successCriteria:
      - condition: $statusCode == 200
禁用特定测试

使用 overlay 禁用某个生成的测试,而不删除它:

overlay: 1.0.0
info:
  title: Disable flaky test
actions:
  - target: $["workflows"][?(@.workflowId=="flaky-test")]
    update:
      x-speakeasy-test:
        disabled: true
3. 集成测试

对于实时 API 测试,请使用 SDK 工厂模式:

TypeScript 示例:

import { SDK } from "./src";

function createTestClient(): SDK {
  return new SDK({
    apiKey: process.env.TEST_API_KEY,
    serverURL: process.env.TEST_API_URL ?? "https://api.example.com",
  });
}

describe("Integration Tests", () => {
  const client = createTestClient();

  it("should list resources", async () => {
    const result = await client.resources.list({ limit: 5 });
    expect(result.statusCode).toBe(200);
    expect(result.data).toBeDefined();
  });

  it("should create and delete resource", async () => {
    // Create
    const created = await client.resources.create({ name: "integration-test" });
    expect(created.statusCode).toBe(201);

    // Cleanup
    const deleted = await client.resources.delete({ id: created.data.id });
    expect(deleted.statusCode).toBe(204);
  });
});

Python 示例:

import os
import pytest
from my_sdk import SDK

@pytest.fixture
def client():
    return SDK(
        api_key=os.environ["TEST_API_KEY"],
        server_url=os.environ.get("TEST_API_URL", "https://api.example.com"),
    )

def test_list_resources(client):
    result = client.resources.list(limit=5)
    assert result.status_code == 200
    assert result.data is not None

@pytest.mark.cleanup
def test_create_and_delete(client):
    created = client.resources.create(name="integration-test")
    assert created.status_code == 201
    try:
        fetched = client.resources.get(id=created.data.id)
        assert fetched.data.name == "integration-test"
    finally:
        client.resources.delete(id=created.data.id)

用于集成测试的 GitHub Actions CI:

name: Integration Tests
on:
  schedule:
    - cron: "0 6 * * 1-5"
  workflow_dispatch:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: speakeasy-api/sdk-generation-action@v15
        with:
          speakeasy_version: latest
      - run: speakeasy test
        env:
          SPEAKEASY_API_KEY: ${{ secrets.SPEAKEASY_API_KEY }}
      - name: Run integration tests
        run: npm test -- --grep "integration"
        env:
          TEST_API_KEY: ${{ secrets.TEST_API_KEY }}
          TEST_API_URL: ${{ secrets.TEST_API_URL }}

不要做的事

  • 不要跳过契约测试,直接进行集成测试——契约测试无需额外成本,而且能发现大多数问题
  • 不要在 Arazzo 测试文件中硬编码 API 密钥或机密信息——请使用 $env.VARIABLE_NAME 语法
  • 不要直接修改自动生成的测试文件——重新生成时这些文件会被覆盖;请改用自定义 Arazzo 测试
  • 不要在未调查原因前禁用失败的契约测试——ResponseValidationError 通常意味着规范与 API 不一致
  • 不要在生产环境中运行包含破坏性操作的集成测试——务必使用测试/预发布环境
  • 不要假设所有语言都支持契约测试——目前支持的语言有:TypeScript、Python、Go、Java

故障排除

契约测试中的 ResponseValidationError

SDK 响应与 OpenAPI 规范不匹配。常见原因:

  1. 规范已过时:根据最新的 API 规范重新生成
  2. 缺少必填字段:检查规范中的 required 数组是否与实际 API 响应一致
  3. 类型不匹配:检查架构定义中的 type 和 format 字段
# Regenerate with latest spec and re-run tests
speakeasy run --output console && speakeasy test --verbose
测试在本地通过,但在 CI 中失败
  1. 检查是否已在 CI 密钥中设置所有环境变量
  2. 确认 CI 运行器可以通过网络访问模拟服务端口
  3. 确保本地与 CI 中的 Speakeasy CLI 版本一致
找不到 speakeasy test 命令

更新 Speakeasy CLI:

speakeasy update
模拟服务无法启动
  1. 检查默认模拟服务端口是否存在冲突
  2. 确保 OpenAPI 规范有效:speakeasy lint openapi -s spec.yaml
  3. 确认 generateTests: true 已在 gen.yaml 中设置,且 SDK 已重新生成
自定义 Arazzo 测试未运行
  1. 确认文件位于 .speakeasy/tests.arazzo.yaml
  2. 检查 operationId 值是否与 OpenAPI 规范中的值完全一致
  3. 验证 YAML 语法——缩进错误是最常见的原因
集成测试间歇性失败
  1. 为依赖网络的测试添加重试逻辑
  2. 使用包含时间戳的唯一资源名称,避免冲突
  3. 确保测试失败时也会执行清理(使用 finally 或 afterEach)

评论

支持 Markdown