Files

23 KiB

API Checker

Инструмент для автоматизированного end-to-end тестирования API через GitHub Actions.


Содержание


Архитектура

YAML/OpenAPI/Postman → Parser → TestModel → Context → Runner → TestResult

Models

AuthModel

Файл: models/itm.py

Модель аутентификации.

Поле Тип По умолчанию Описание
type str "none" Тип аутентификации: none, basic, bearer, api_key, oauth2
credentials dict[str, str] {} Данные для аутентификации

Когда использовать: Когда API требует аутентификацию. Передаётся в TestModel.auth.


RequestModel

Файл: models/itm.py

Модель HTTP запроса.

Поле Тип По умолчанию Описание
method str "GET" HTTP метод: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS
path str "/" Путь URL (поддерживает {{variable}})
headers dict[str, str] {} HTTP заголовки
query dict[str, str] {} Query параметры
body dict | str | None None Тело запроса
body_type str "json" Тип тела: json, form, raw
timeout int 30 Таймаут в секундах

Когда использовать: Определяет что отправить серверу. Передаётся в StepModel.request.


ExtractModel

Файл: models/itm.py

Модель извлечения данных из ответа.

Поле Тип По умолчанию Описание
name str — Имя переменной (обязательное)
json_path str — JSON-путь к значению: $.token, $.user.id (обязательное)
source str "body" Источник: body, header, status

Когда использовать: Когда нужно сохранить данные из ответа для использования в следующих запросах. Передаётся в StepModel.extract.


AssertModel

Файл: models/itm.py

Модель проверки ответа.

Поле Тип По умолчанию Описание
type str — Тип проверки: status, json, header (обязательное)
path str | None None JSON-путь к полю для проверки
operator str "equals" Оператор: equals, exists, gt, lt, contains, matches
value Any None Ожидаемое значение

Когда использовать: Когда нужно проверить что ответ соответствует ожиданиям. Передаётся в StepModel.assert_.


StepModel

Файл: models/itm.py

Модель одного шага теста.

Поле Тип По умолчанию Описание
name str — Название шага (обязательное)
request RequestModel — HTTP запрос (обязательное)
extract list[ExtractModel] [] Извлечение данных
assert_ list[AssertModel] [] Проверки

Когда использовать: Один логический шаг теста (например, "Залогиниться"). Передаётся в TestModel.steps.


TestModel

Файл: models/itm.py

Основная модель теста. Содержит всю конфигурацию.

Поле Тип По умолчанию Описание
name str "Unnamed Test" Название теста
base_url str "" Базовый URL API
variables dict[str, str] {} Статические переменные
auth AuthModel | None None Аутентификация
steps list[StepModel] [] Шаги теста

Когда использовать: Главная входная точка. Создаётся парсерами или вручную.


Context

Файл: models/context.py

Контекст выполнения. Хранит состояние во время запуска теста.

Поле Тип Описание
config TestModel Оригинальная конфигурация теста
variables dict[str, str] Статические переменные из config
extracted dict[str, Any] Извлечённые данные из ответов

Методы:

Метод Вход Возврат Описание
__init__(config) TestModel — Создаёт контекст из конфигурации
resolve(template) str str Заменяет {{var}} на значение из variables или extracted
set_extracted(name, value) str, Any — Сохраняет извлечённое значение

Когда использовать: Передаётся всем компонентам (Executor, Extractor, TestRunner) для доступа к данным.

Пример:

context = Context(TestModel(variables={"email": "test@x.com"}))
context.set_extracted("token", "abc123")

context.resolve("{{email}}")      # "test@x.com"
context.resolve("Bearer {{token}}")  # "Bearer abc123"

Response

Файл: models/executor.py

Модель HTTP ответа.

Поле Тип Описание
status int HTTP статус-код (200, 404, ...)
body dict Тело ответа (JSON)
headers dict Заголовки ответа

Когда использовать: Создаётся Executor после выполнения запроса. Передаётся в Extractor и Validator.


Executor

Файл: models/executor.py

Выполняет HTTP запросы.

Метод Вход Возврат Описание
__init__(context) Context — Создаёт executor с контекстом
_resolve_url(request) RequestModel str Разрешает URL с переменными
execute(request) RequestModel Response Выполняет HTTP запрос

Когда использовать: Отправляет запросы к API. Используется TestRunner.

Пример:

context = Context(model)
executor = Executor(context)
response = executor.execute(RequestModel(method="GET", path="/api/users"))
print(response.status)  # 200

Extractor

Файл: models/extractor.py

Извлекает данные из HTTP ответов.

Метод Вход Возврат Описание
__init__(context) Context — Создаёт extractor с контекстом
extract(configs, response) list[ExtractModel], Response — Извлекает данные в context.extracted

Внутренние методы:

Метод Вход Возврат Описание
_get_value(response, config) Response, ExtractModel Any Получает значение из ответа
_json_path(data, path) dict, str Any Извлекает значение по JSON-пути

Когда использовать: Когда нужно сохранить данные из ответа (токен, ID, ...) для использования в следующих шагах.

Пример:

extractor = Extractor(context)
response = Response(status=200, body={"token": "abc123"}, headers={})
extractor.extract([ExtractModel(name="token", json_path="$.token")], response)

print(context.extracted["token"])  # "abc123"

Validator

Файл: models/validator.py

Проверяет HTTP ответы.

Метод Вход Возврат Описание
validate(asserts, response) list[AssertModel], Response bool Все ли проверки прошли

Внутренние методы:

Метод Вход Возврат Описание
_check(assertion, response) AssertModel, Response bool Проверяет одно утверждение

Когда использовать: Проверяет что ответ соответствует ожиданиям. Используется TestRunner.

Пример:

validator = Validator()
response = Response(status=200, body={}, headers={})
asserts = [AssertModel(type="status", value=200)]

print(validator.validate(asserts, response))  # True

StepResult

Файл: models/runner.py

Результат выполнения одного шага.

Поле Тип Описание
name str Название шага
passed bool Прошёл ли шаг
response Response HTTP ответ

Когда использовать: Создаётся TestRunner после выполнения шага. Возвращается в TestResult.


TestResult

Файл: models/runner.py

Результат выполнения всего теста.

Поле Тип Описание
steps list[StepResult] Результаты всех шагов

Свойства:

Свойство Тип Описание
passed bool True если все шаги прошли

Когда использовать: Возвращается TestRunner.run(). Используется для вывода результатов.


TestRunner

Файл: models/runner.py

Оркестратор выполнения теста.

Метод Вход Возврат Описание
__init__(context) Context — Создаёт runner с контекстом
run() — TestResult Запускает все шаги теста

Когда использовать: Главная точка входа для запуска теста.

Пример:

context = Context(model)
runner = TestRunner(context)
result = runner.run()

print(result.passed)  # True/False
for step in result.steps:
    print(f"{step.name}: {'OK' if step.passed else 'FAIL'}")

YAML Readers

ParseError

Файл: yamlreaders/base.py

Исключение при ошибке парсинга.

Поле Тип Описание
line int | None Номер строки с ошибкой

Когда использовать: Ловить при парсинге невалидных YAML файлов.


BaseReader

Файл: yamlreaders/base.py

Абстрактный базовый класс для всех парсеров.

Метод Вход Возврат Описание
validate(source) str | Path bool Проверяет валидность файла
parse(source) str | Path TestModel Конвертирует файл в TestModel
load_yaml(source) str | Path dict Загружает YAML файл

Исключения:

  • FileNotFoundError — файл не найден
  • ParseError — ошибка парсинга

Когда использовать: Не используется напрямую. Используйте наследников (YamlReader, PostmanReader, OpenAPIReader).


YamlReader

Файл: yamlreaders/yaml_reader.py

Парсер для кастомного формата YAML.

Метод Вход Возврат Описание
validate(source) str | Path bool Проверяет наличие steps, request, method
parse(source) str | Path TestModel Парсит YAML в TestModel

Внутренние методы:

Метод Вход Возврат Описание
_parse_steps(steps) list[dict] list[StepModel] Парсит шаги
_parse_request(request) dict RequestModel Парсит запрос
_parse_extract(extract) list[dict] list[ExtractModel] Парсит извлечение
_parse_assert(asserts) list[dict] list[AssertModel] Парсит проверки

Формат YAML:

name: "Test Name"
base_url: http://localhost:8080
variables:
  email: test@example.com

steps:
  - name: "Login"
    request:
      method: POST
      url: /api/login
      headers:
        Content-Type: application/json
      body:
        email: "{{email}}"
    extract:
      - name: token
        json_path: "$.token"
    assert:
      - type: status
        value: 200

Когда использовать: Для собственных тест-спецификаций проекта.


PostmanReader

Файл: yamlreaders/postman_reader.py

Парсер для Postman Collection v2/v2.1.

Метод Вход Возврат Описание
validate(source) str | Path bool Проверяет наличие info и item
parse(source) str | Path TestModel Парсит Postman Collection в TestModel

Внутренние методы:

Метод Вход Возврат Описание
_extract_variables(data) dict dict[str, str] Извлекает переменные
_extract_base_url(data) dict str Ищет переменную base_url
_extract_auth(data) dict AuthModel | None Парсит аутентификацию
_parse_items(items) list[dict] list[StepModel] Рекурсивно парсит items
_parse_item(item) dict StepModel | None Парсит один request
_parse_request(request) dict RequestModel Парсит HTTP запрос
_parse_events(events) list[dict] list[ExtractModel] Парсит test scripts
_parse_test_script(line) str list[ExtractModel] | None Извлекает pm.environment.set()
_convert_pm_to_json_path(pm_expr) str str Конвертирует pm表达式 в JSON-путь

Формат YAML:

info:
  name: "Collection Name"

variable:
  - key: base_url
    value: http://localhost:8080

item:
  - name: "Login"
    request:
      method: POST
      url:
        raw: "{{base_url}}/api/login"
        path:
          - api
          - login
      header:
        - key: Content-Type
          value: application/json
      body:
        mode: raw
        raw: '{"email": "{{email}}"}'
    event:
      - listen: test
        script:
          exec:
            - "pm.environment.set('token', pm.response.json().token);"

Когда использовать: Для импорта коллекций из Postman.


OpenAPIReader

Файл: yamlreaders/openapi_reader.py

Парсер для OpenAPI 3.0/3.1 спецификаций.

Метод Вход Возврат Описание
validate(source) str | Path bool Проверяет наличие openapi и paths
parse(source) str | Path TestModel Парсит OpenAPI в TestModel

Внутренние методы:

Метод Вход Возврат Описание
_extract_base_url(data) dict str Берёт URL из servers
_extract_auth(data) dict AuthModel | None Парсит securitySchemes
_parse_paths(paths) dict list[StepModel] Конвертирует paths в шаги
_parse_operation(path, method, operation) str, str, dict StepModel Парсит один operation
_build_request(path, method, operation) str, str, dict RequestModel Создаёт RequestModel
_schema_to_example(schema) dict dict Создаёт example из schema
_generate_extracts(operation) dict list[ExtractModel] Генерирует extraction
_generate_asserts(operation) dict list[AssertModel] Генерирует asserts

Формат YAML:

openapi: "3.0.0"
info:
  title: "API Name"
  version: "1.0.0"

servers:
  - url: http://localhost:8080

paths:
  /api/login:
    post:
      operationId: "loginUser"
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
      responses:
        "200":
          description: "Success"
          content:
            application/json:
              schema:
                type: object
                properties:
                  token:
                    type: string

Когда использовать: Для импорта API из OpenAPI спецификаций.


get_reader

Файл: yamlreaders/__init__.py

Функция для автоопределения формата и получения appropriate reader.

Параметр Тип Описание
source str Путь к YAML файлу

Возврат: BaseReader (YamlReader, PostmanReader или OpenAPIReader)

Исключения:

  • FileNotFoundError — файл не найден

Логика определения:

Признак Формат Reader
openapi: в содержимом OpenAPI OpenAPIReader
info и item в YAML Postman PostmanReader
Иначе Кастомный YAML YamlReader

Когда использовать: Когда нужно автоматически определить формат файла.

Пример:

from yamlreaders import get_reader

reader = get_reader("tests/api.yaml")
model = reader.parse("tests/api.yaml")

Примеры использования

Базовый пример

from models import TestModel, StepModel, RequestModel, ExtractModel, AssertModel
from models import Context, TestRunner

# Создаём модель теста
model = TestModel(
    name="Тест логина",
    base_url="http://localhost:8080",
    variables={"email": "test@x.com", "password": "123456"},
    steps=[
        StepModel(
            name="Логин",
            request=RequestModel(
                method="POST",
                path="/api/login",
                body={"email": "{{email}}", "password": "{{password}}"}
            ),
            extract=[
                ExtractModel(name="token", json_path="$.token")
            ],
            assert_=[
                AssertModel(type="status", value=200)
            ]
        )
    ]
)

# Запускаем
context = Context(model)
runner = TestRunner(context)
result = runner.run()

# Результат
print(f"Тест: {result.passed}")

Парсинг из YAML

from yamlreaders import get_reader
from models import Context, TestRunner

# Автоопределение формата
reader = get_reader("tests/api.yaml")
model = reader.parse("tests/api.yaml")

# Запуск
context = Context(model)
runner = TestRunner(context)
result = runner.run()

print(result.passed)

Парсинг из Postman

from yamlreaders import PostmanReader
from models import Context, TestRunner

reader = PostmanReader()
model = reader.parse("exports/postman_collection.yaml")

context = Context(model)
result = TestRunner(context).run()

Парсинг из OpenAPI

from yamlreaders import OpenAPIReader
from models import Context, TestRunner

reader = OpenAPIReader()
model = reader.parse("docs/openapi.yaml")

context = Context(model)
result = TestRunner(context).run()

Использование переменных

model = TestModel(
    variables={"host": "localhost"},
    steps=[
        StepModel(
            name="Запрос",
            request=RequestModel(
                method="GET",
                path="http://{{host}}:8080/api/users"
            )
        )
    ]
)

context = Context(model)
context.resolve("{{host}}")  # "localhost"

Извлечение данных

from models import Extractor, Response, ExtractModel

context = Context(model)
extractor = Extractor(context)

response = Response(
    status=200,
    body={"user": {"id": 123, "name": "Test"}},
    headers={}
)

extractor.extract([
    ExtractModel(name="user_id", json_path="$.user.id")
], response)

print(context.extracted["user_id"])  # 123

Проверка ответов

from models import Validator, Response, AssertModel

validator = Validator()
response = Response(status=200, body={}, headers={})

# Проверка статуса
asserts = [AssertModel(type="status", value=200)]
print(validator.validate(asserts, response))  # True