# API Checker Инструмент для автоматизированного end-to-end тестирования API через GitHub Actions. --- ## Содержание - [Архитектура](#архитектура) - [Models](#models) - [AuthModel](#authmodel) - [RequestModel](#requestmodel) - [ExtractModel](#extractmodel) - [AssertModel](#assertmodel) - [StepModel](#stepmodel) - [TestModel](#testmodel) - [Context](#context) - [Response](#response) - [Executor](#executor) - [Extractor](#extractor) - [Validator](#validator) - [StepResult](#stepresult) - [TestResult](#testresult) - [TestRunner](#testrunner) - [YAML Readers](#yaml-readers) - [ParseError](#parseerror) - [BaseReader](#basereader) - [YamlReader](#yamlreader) - [PostmanReader](#postmanreader) - [OpenAPIReader](#openapireader) - [get_reader](#get_reader) - [Примеры использования](#примеры-использования) --- ## Архитектура ``` 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) для доступа к данным. **Пример:** ```python 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. **Пример:** ```python 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, ...) для использования в следующих шагах. **Пример:** ```python 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. **Пример:** ```python 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` | Запускает все шаги теста | **Когда использовать:** Главная точка входа для запуска теста. **Пример:** ```python 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:** ```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:** ```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:** ```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 | **Когда использовать:** Когда нужно автоматически определить формат файла. **Пример:** ```python from yamlreaders import get_reader reader = get_reader("tests/api.yaml") model = reader.parse("tests/api.yaml") ``` --- ## Примеры использования ### Базовый пример ```python 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 ```python 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 ```python 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 ```python from yamlreaders import OpenAPIReader from models import Context, TestRunner reader = OpenAPIReader() model = reader.parse("docs/openapi.yaml") context = Context(model) result = TestRunner(context).run() ``` ### Использование переменных ```python 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" ``` ### Извлечение данных ```python 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 ``` ### Проверка ответов ```python 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 ```