- BaseReader abstract class - YamlReader for custom YAML format - PostmanReader for Postman Collection v2.1 - OpenAPIReader for OpenAPI 3.0/3.1 - get_reader() auto-detection function - Usage examples for each reader
450 lines
12 KiB
Markdown
450 lines
12 KiB
Markdown
# API Checker - Models
|
|
|
|
## Архитектура
|
|
|
|
Данные flowing через систему:
|
|
|
|
```
|
|
YAML/OpenAPI/Postman → Parser → TestModel → Context → Runner → TestResult
|
|
```
|
|
|
|
## Классы
|
|
|
|
### TestModel (models/itm.py)
|
|
|
|
Основная структура теста.
|
|
|
|
| Поле | Тип | Описание |
|
|
|------|-----|----------|
|
|
| name | str | Название теста |
|
|
| base_url | str | Базовый URL |
|
|
| variables | dict | Переменные |
|
|
| steps | list[StepModel] | Шаги теста |
|
|
|
|
### StepModel (models/itm.py)
|
|
|
|
Один шаг теста.
|
|
|
|
| Поле | Тип | Описание |
|
|
|------|-----|----------|
|
|
| name | str | Название шага |
|
|
| request | RequestModel | HTTP запрос |
|
|
| extract | list[ExtractModel] | Извлечение данных |
|
|
| assert_ | list[AssertModel] | Проверки |
|
|
|
|
### RequestModel (models/itm.py)
|
|
|
|
HTTP запрос.
|
|
|
|
| Поле | Тип | Описание |
|
|
|------|-----|----------|
|
|
| method | str | GET, POST, PUT... |
|
|
| path | str | Путь URL |
|
|
| headers | dict | Заголовки |
|
|
| body | dict | Тело запроса |
|
|
| timeout | int | Таймаут |
|
|
|
|
### ExtractModel (models/itm.py)
|
|
|
|
Извлечение данных из ответа.
|
|
|
|
| Поле | Тип | Описание |
|
|
|------|-----|----------|
|
|
| name | str | Имя переменной |
|
|
| json_path | str | Путь к значению |
|
|
| source | str | body/header/status |
|
|
|
|
### AssertModel (models/itm.py)
|
|
|
|
Проверка ответа.
|
|
|
|
| Поле | Тип | Описание |
|
|
|------|-----|----------|
|
|
| type | str | status/json/header |
|
|
| path | str | Путь к полю |
|
|
| operator | str | equals/exists/gt/lt |
|
|
| value | Any | Ожидаемое значение |
|
|
|
|
### Context (models/context.py)
|
|
|
|
Контекст выполнения.
|
|
|
|
| Поле | Тип | Описание |
|
|
|------|-----|----------|
|
|
| config | TestModel | Конфигурация |
|
|
| variables | dict | Статические переменные |
|
|
| extracted | dict | Извлечённые данные |
|
|
|
|
| Метод | Описание |
|
|
|-------|----------|
|
|
| resolve(template) | Заменяет {{var}} на значение |
|
|
| set_extracted(name, value) | Сохраняет извлечённое |
|
|
|
|
### Executor (models/executor.py)
|
|
|
|
Выполняет HTTP запросы.
|
|
|
|
| Метод | Описание |
|
|
|-------|----------|
|
|
| execute(request) → Response | Выполняет запрос |
|
|
|
|
### Extractor (models/extractor.py)
|
|
|
|
Извлекает данные из ответов.
|
|
|
|
| Метод | Описание |
|
|
|-------|----------|
|
|
| extract(configs, response) | Извлекает данные в Context |
|
|
|
|
### Validator (models/validator.py)
|
|
|
|
Проверяет ответы.
|
|
|
|
| Метод | Описание |
|
|
|-------|----------|
|
|
| validate(asserts, response) → bool | Все ли проверки прошли |
|
|
|
|
### TestRunner (models/runner.py)
|
|
|
|
Оркестратор.
|
|
|
|
| Метод | Описание |
|
|
|-------|----------|
|
|
| run() → TestResult | Запускает тест |
|
|
|
|
## Пример использования
|
|
|
|
```python
|
|
from models import TestModel, StepModel, RequestModel, ExtractModel, TestRunner, Context
|
|
|
|
config = TestModel(
|
|
base_url="http://localhost:8080",
|
|
variables={"email": "test@x.com"},
|
|
steps=[
|
|
StepModel(
|
|
name="Login",
|
|
request=RequestModel(method="POST", path="/login"),
|
|
extract=[ExtractModel(name="token", json_path="$.token")],
|
|
)
|
|
]
|
|
)
|
|
|
|
context = Context(config)
|
|
runner = TestRunner(context)
|
|
result = runner.run()
|
|
|
|
print(result.passed) # True/False
|
|
```
|
|
|
|
---
|
|
|
|
# YAML Readers (yamlreaders/)
|
|
|
|
## Обзор
|
|
|
|
Модуль для парсинга тест-спецификаций из различных форматов и конвертации их во внутреннюю модель `TestModel`.
|
|
|
|
Поддерживаемые форматы:
|
|
- **Кастомный YAML** — собственный формат проекта
|
|
- **Postman Collection v2.1** — экспорт из Postman
|
|
- **OpenAPI 3.0/3.1** — спецификация API
|
|
|
|
## Архитектура
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────┐
|
|
│ YAML Readers │
|
|
│ ┌─────────────┐ ┌─────────────┐ ┌──────────┐│
|
|
│ │ YamlReader │ │ PostmanReader│ │OpenAPIReader│
|
|
│ └──────┬──────┘ └──────┬──────┘ └─────┬────┘│
|
|
│ └────────────────┼────────────────┘ │
|
|
│ ▼ │
|
|
│ TestModel (ITM) │
|
|
└─────────────────────────────────────────────────┘
|
|
```
|
|
|
|
## Классы
|
|
|
|
### BaseReader (yamlreaders/base.py)
|
|
|
|
Абстрактный базовый класс для всех парсеров.
|
|
|
|
| Метод | Возвращаемое значение | Описание |
|
|
|-------|----------------------|----------|
|
|
| validate(source) | bool | Проверяет валидность файла |
|
|
| parse(source) | TestModel | Конвертирует файл в TestModel |
|
|
| load_yaml(source) | dict | Загружает YAML файл |
|
|
|
|
**Параметры:**
|
|
- `source: str | Path` — путь к YAML файлу
|
|
|
|
**Исключения:**
|
|
- `FileNotFoundError` — файл не найден
|
|
- `ParseError` — ошибка парсинга YAML
|
|
|
|
---
|
|
|
|
### YamlReader (yamlreaders/yaml_reader.py)
|
|
|
|
Парсер для кастомного формата YAML проекта.
|
|
|
|
**Формат входного файла:**
|
|
|
|
```yaml
|
|
name: "Test Name"
|
|
base_url: http://localhost:8080
|
|
variables:
|
|
email: test@example.com
|
|
password: Test123!
|
|
|
|
steps:
|
|
- name: "Step Name"
|
|
request:
|
|
method: POST
|
|
url: /api/endpoint
|
|
headers:
|
|
Content-Type: application/json
|
|
body:
|
|
key: value
|
|
timeout: 30
|
|
extract:
|
|
- name: variable_name
|
|
json_path: "$.field"
|
|
source: body
|
|
assert:
|
|
- type: status
|
|
value: 200
|
|
- type: json
|
|
path: "$.id"
|
|
operator: exists
|
|
```
|
|
|
|
**Методы:**
|
|
|
|
| Метод | Возвращаемое значение | Описание |
|
|
|-------|----------------------|----------|
|
|
| validate(source) | bool | Проверяет наличие steps, request, method |
|
|
| parse(source) | TestModel | Парсит YAML в TestModel |
|
|
|
|
**Пример использования:**
|
|
|
|
```python
|
|
from yamlreaders import YamlReader
|
|
|
|
reader = YamlReader()
|
|
|
|
# Проверка валидности
|
|
if reader.validate("tests/api.yaml"):
|
|
model = reader.parse("tests/api.yaml")
|
|
print(model.name, len(model.steps))
|
|
```
|
|
|
|
---
|
|
|
|
### PostmanReader (yamlreaders/postman_reader.py)
|
|
|
|
Парсер для Postman Collection v2/v2.1.
|
|
|
|
**Формат входного файла (YAML):**
|
|
|
|
```yaml
|
|
info:
|
|
name: "Collection Name"
|
|
schema: "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
|
|
|
variable:
|
|
- key: base_url
|
|
value: http://localhost:8080
|
|
- key: email
|
|
value: test@example.com
|
|
|
|
item:
|
|
- name: "Request Name"
|
|
request:
|
|
method: POST
|
|
url:
|
|
raw: "{{base_url}}/api/login"
|
|
host:
|
|
- "{{base_url}}"
|
|
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);"
|
|
```
|
|
|
|
**Методы:**
|
|
|
|
| Метод | Возвращаемое значение | Описание |
|
|
|-------|----------------------|----------|
|
|
| validate(source) | bool | Проверяет наличие info и item |
|
|
| parse(source) | TestModel | Парсит Postman Collection в TestModel |
|
|
|
|
**Особенности парсинга:**
|
|
|
|
| Функция | Описание |
|
|
|---------|----------|
|
|
| Extract variables | Извлекает переменные из `variable[]` |
|
|
| Extract base_url | Ищет переменную `base_url` |
|
|
| Parse nested items | Рекурсивно обходит вложенные папки |
|
|
| Parse request body | Конвертирует `raw`, `urlencoded`, `formdata` |
|
|
| Parse test scripts | Извлекает `pm.environment.set()` для extraction |
|
|
|
|
**Пример использования:**
|
|
|
|
```python
|
|
from yamlreaders import PostmanReader
|
|
|
|
reader = PostmanReader()
|
|
|
|
if reader.validate("exports/collection.yaml"):
|
|
model = reader.parse("exports/collection.yaml")
|
|
print(model.name, len(model.steps))
|
|
```
|
|
|
|
---
|
|
|
|
### OpenAPIReader (yamlreaders/openapi_reader.py)
|
|
|
|
Парсер для OpenAPI 3.0/3.1 спецификаций.
|
|
|
|
**Формат входного файла (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"
|
|
summary: "Login user"
|
|
requestBody:
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
email:
|
|
type: string
|
|
password:
|
|
type: string
|
|
responses:
|
|
"200":
|
|
description: "Success"
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
token:
|
|
type: string
|
|
```
|
|
|
|
**Методы:**
|
|
|
|
| Метод | Возвращаемое значение | Описание |
|
|
|-------|----------------------|----------|
|
|
| validate(source) | bool | Проверяет наличие openapi и paths |
|
|
| parse(source) | TestModel | Парсит OpenAPI в TestModel |
|
|
|
|
**Особенности парсинга:**
|
|
|
|
| Функция | Описание |
|
|
|---------|----------|
|
|
| Extract base_url | Берёт URL из `servers[0]` |
|
|
| Extract auth | Парсит `securitySchemes` (basic, bearer, apiKey, oauth2) |
|
|
| Parse paths | Конвертирует все methods (GET, POST, PUT...) в шаги |
|
|
| Generate request body | Создаёт example body из `schema` |
|
|
| Generate asserts | Автоматически добавляет проверку status code |
|
|
| Generate extracts | Извлекает поля из response schema |
|
|
|
|
**Пример использования:**
|
|
|
|
```python
|
|
from yamlreaders import OpenAPIReader
|
|
|
|
reader = OpenAPIReader()
|
|
|
|
if reader.validate("docs/openapi.yaml"):
|
|
model = reader.parse("docs/openapi.yaml")
|
|
print(model.name, len(model.steps))
|
|
```
|
|
|
|
---
|
|
|
|
## Автоопределение формата
|
|
|
|
Функция `get_reader()` автоматически определяет формат файла и возвращаетappropriate reader.
|
|
|
|
```python
|
|
from yamlreaders import get_reader
|
|
|
|
reader = get_reader("tests/api.yaml")
|
|
model = reader.parse("tests/api.yaml")
|
|
```
|
|
|
|
**Логика определения:**
|
|
|
|
| Признак | Формат | Reader |
|
|
|---------|--------|--------|
|
|
| `openapi:` в первой строке | OpenAPI | OpenAPIReader |
|
|
| `"info"` и `"item"` в JSON | Postman | PostmanReader |
|
|
| Иначе | Кастомный YAML | YamlReader |
|
|
|
|
---
|
|
|
|
## Исключения
|
|
|
|
### ParseError
|
|
|
|
Выбрасывается при ошибке парсинга YAML.
|
|
|
|
```python
|
|
from yamlreaders.base import ParseError
|
|
|
|
try:
|
|
model = reader.parse("invalid.yaml")
|
|
except ParseError as e:
|
|
print(f"Error at line {e.line}: {e}")
|
|
```
|
|
|
|
---
|
|
|
|
## Полный пример
|
|
|
|
```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()
|
|
|
|
# Выводим результат
|
|
for step in result.steps:
|
|
status = "✓" if step.passed else "✗"
|
|
print(f"{status} {step.name}")
|
|
|
|
print(f"\n{'PASSED' if result.passed else 'FAILED'}")
|
|
```
|