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