Modern QA2026От OpenAPI-схемы к набору тестов
Join

Course04 API & Contract Testing with AI

Cutting-edge · Chapter 04

От OpenAPI-схемы к набору тестов

Updated Jul 2026

Почему OpenAPI -- идеальный входной формат для ИИ

OpenAPI (Swagger) схема -- это машиночитаемый контракт. Она определяет конечные точки, методы, структуры запросов/ответов, требования аутентификации и коды ошибок. Это делает её идеальным входным форматом для генерации тестов с помощью ИИ, потому что каждое ограничение в схеме напрямую отображается в тестовый сценарий.

В отличие от требований на естественном языке, OpenAPI-схемы однозначны. Поле, определённое как type: integer, minimum: 0, maximum: 100, не оставляет места для интерпретации. ИИ может механически перечислить каждое граничное значение, несоответствие типов и сценарий отсутствия поля.

Конвейер анализа

OpenAPI Schema (YAML/JSON)
    |
    v
+---------------------------+
|  AI SCHEMA ANALYZER       |
|                           |
| 1. Parse endpoints        |
| 2. Extract constraints    |
| 3. Identify edge cases    |
| 4. Map auth requirements  |
| 5. Detect undocumented    |
|     patterns              |
+----------+----------------+
           |
           v
+---------------------------+
|  TEST GENERATOR           |
|                           |
|  Per endpoint:            |
|  - Happy path tests       |
|  - Validation tests       |
|  - Auth tests             |
|  - Boundary tests         |
|  - Error code tests       |
+---------------------------+

Шаг 1: Разбор конечных точек

Извлеките каждую комбинацию путь + метод:

def parse_endpoints(spec: dict) -> list[Endpoint]:
    endpoints = []
    for path, methods in spec["paths"].items():
        for method, details in methods.items():
            if method in ("get", "post", "put", "patch", "delete"):
                endpoints.append(Endpoint(
                    path=path,
                    method=method.upper(),
                    summary=details.get("summary", ""),
                    parameters=details.get("parameters", []),
                    request_body=details.get("requestBody"),
                    responses=details.get("responses", {}),
                    security=details.get("security", []),
                ))
    return endpoints

Шаг 2: Извлечение ограничений

Для каждого поля в телах запросов и параметрах определите тестируемые ограничения:

Свойство схемы Генерируемые тестовые сценарии
required: true Тест с отсутствующим полем, null, пустым значением
type: string Тест с числом, boolean, массивом, объектом
minLength: 1 Тест с пустой строкой, строкой из 1 символа
maxLength: 200 Тест с 200 символами, 201 символом
minimum: 0 Тест с -1, 0, 1
maximum: 100 Тест с 99, 100, 101
format: uuid Тест с валидным UUID, невалидным UUID, пустым
format: email Тест с валидным email, невалидным email
enum: [a, b, c] Тест каждого значения + одно невалидное значение
pattern: "^[A-Z]{3}$" Тест совпадающих и несовпадающих строк

Шаг 3: Маппинг требований аутентификации

# Schema defines auth per endpoint:
security:
  - BearerAuth: [admin]

# This generates tests:
# 1. Valid admin token → 200
# 2. Valid user token (wrong role) → 403
# 3. Expired token → 401
# 4. Missing token → 401
# 5. Malformed token → 401

Промпт

Analyze this OpenAPI 3.0 schema and generate a comprehensive test suite.

```yaml
openapi: 3.0.3
paths:
  /api/v2/products/{id}:
    get:
      summary: Get product by ID
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Product found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Product'
        '404':
          description: Product not found
        '401':
          description: Unauthorized
    put:
      summary: Update product
      security:
        - BearerAuth: [admin]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ProductUpdate'
      responses:
        '200':
          description: Updated
        '400':
          description: Validation error
        '403':
          description: Forbidden (not admin)

components:
  schemas:
    Product:
      type: object
      properties:
        id: { type: string, format: uuid }
        name: { type: string, minLength: 1, maxLength: 200 }
        price: { type: number, minimum: 0 }
        category: { type: string, enum: [electronics, clothing, food, other] }
        in_stock: { type: boolean }
    ProductUpdate:
      type: object
      required: [name, price]
      properties:
        name: { type: string, minLength: 1, maxLength: 200 }
        price: { type: number, minimum: 0 }
        category: { type: string, enum: [electronics, clothing, food, other] }

Generate tests using pytest + httpx. For each endpoint and method, include:

  1. Happy path with valid data
  2. Every documented error response (trigger each status code)
  3. Boundary values for constrained fields (minLength, maxLength, minimum)
  4. Type mismatch tests (string where number expected, etc.)
  5. Missing required field tests
  6. Invalid enum value tests
  7. Auth tests (missing token, expired token, wrong role)


## Что ИИ находит, а люди пропускают

| Инсайт | Как ИИ обнаруживает | Влияние |
|---------|---------------------|---------|
| Недокументированные ошибки 500 | Систематически отправляет данные с несоответствием типов | Выявляет отсутствующую валидацию ввода |
| Несогласованные форматы ошибок | Сравнивает структуры ответов об ошибках между конечными точками | Выявляет технический долг |
| Отсутствующие CORS-заголовки | Тестирует из кроссоригинного контекста | Обнаруживает пробелы в конфигурации деплоя |
| Неотмеченные nullable-поля | Отправляет `null` для каждого поля | Выявляет неполноту схемы |
| Недокументированное поведение rate limit | Отправляет быструю серию идентичных запросов | Документирует операционное поведение |


## Автоматизация конвейера

```python
class SchemaToTestPipeline:
    """Automated pipeline: OpenAPI schema → test suite."""

    def __init__(self, llm, schema_path: str, output_dir: str):
        self.llm = llm
        self.schema = self.load_schema(schema_path)
        self.output_dir = output_dir

    def generate_all(self):
        """Generate test files for every endpoint in the schema."""
        endpoints = self.parse_endpoints(self.schema)

        for endpoint in endpoints:
            test_code = self.llm.generate(f"""
            Generate pytest + httpx tests for:
            Endpoint: {endpoint.method} {endpoint.path}
            Parameters: {endpoint.parameters}
            Request body: {endpoint.request_body}
            Responses: {endpoint.responses}
            Auth: {endpoint.security}

            Full schema context:
            {json.dumps(self.schema['components']['schemas'], indent=2)}

            Include: happy path, all error codes, boundary values,
            type mismatches, missing required fields, auth tests.
            """)

            # Save to file
            filename = self.endpoint_to_filename(endpoint)
            filepath = os.path.join(self.output_dir, filename)
            with open(filepath, "w") as f:
                f.write(test_code)

            print(f"Generated: {filepath} ({endpoint.method} {endpoint.path})")

    def endpoint_to_filename(self, endpoint) -> str:
        """Convert endpoint to a test filename."""
        safe_path = endpoint.path.replace("/", "_").replace("{", "").replace("}", "")
        return f"test_{endpoint.method.lower()}{safe_path}.py"

Валидация: проверка сгенерированных тестов

После генерации проверьте набор тестов:

# 1. Syntax check: do all files parse?
import ast
for test_file in glob("tests/generated/*.py"):
    ast.parse(open(test_file).read())

# 2. Import check: do all imports resolve?
pytest --collect-only tests/generated/

# 3. Execution check: do tests run (even if some fail)?
pytest tests/generated/ -v --tb=short

# 4. Coverage check: did we generate tests for all endpoints?
endpoints_in_schema = set(parse_all_endpoints(schema))
endpoints_tested = set(extract_endpoints_from_tests("tests/generated/"))
missing = endpoints_in_schema - endpoints_tested
if missing:
    print(f"MISSING TESTS for: {missing}")

Ключевой вывод

OpenAPI-схемы -- самый удобный для ИИ входной формат при генерации тестов. Каждое ограничение отображается в тестовый сценарий. Конвейер (разбор конечных точек, извлечение ограничений, генерация тестов, валидация) может быть полностью автоматизирован, где ИИ выполняет основную работу. Роль человека -- проверка сгенерированных тестов на доменную корректность и отсутствие галлюцинированных API.