💻 Примеры: Проект API-тестов с Allure
⚡ Структура проекта API-тестов с Allure
project/
├── api/company_api.py # @allure.step на всех методах API-клиента
├── db/company_table.py # @allure.step на всех методах работы с БД
└── tests/test_x_clients_db.py # тесты с @allure.epic/feature/story + шаги
Ключевой принцип: декорируй методы API-класса через @allure.step — тогда в тестах не нужно писать with allure.step для каждого вызова, Allure покажет их автоматически.
Структура проекта
project/
├── api/
│ └── company_api.py # HTTP-клиент для работы с API компаний
├── db/
│ └── company_table.py # Класс для работы с таблицей company в БД
├── tests/
│ └── test_x_clients_db.py # Тесты с Allure-разметкой
├── allure-results/ # Папка с сырыми данными (создаётся автоматически)
└── allure-report/ # Папка с HTML-отчётом (создаётся при generate)
Пример 1 — Класс CompanyApi с @allure.step
# api/company_api.py
import allure
import requests
class CompanyApi:
def __init__(self, url):
self.url = url
@allure.step("api. Получить список компаний")
def get_company_list(self, params_to_add=None):
my_url = self.url + "/company"
response = requests.get(my_url, params=params_to_add)
return response.json()
@allure.step("api. Получить токен авторизации пользователя '{user}'")
def get_token(self, user="raphael", password="cool-but-crude"):
creds = {"user": user, "password": password}
response = requests.post(self.url + "/auth/login", json=creds)
return response.json()["userToken"]
@allure.step("api. Получить компанию по id '{id}'")
def get_company(self, id):
response = requests.get(self.url + "/company/" + str(id))
return response.json()
@allure.step("api. Создать компанию '{name}' ({description})")
def create_company(self, name, description=""):
token = self.get_token()
headers = {"x-client-token": token}
body = {"name": name, "description": description}
response = requests.post(self.url + "/company", headers=headers, json=body)
return response.json()
@allure.step("api. Редактировать компанию '{new_id}': новое имя '{new_name}'")
def edit(self, new_id, new_name, new_descr):
token = self.get_token()
headers = {"x-client-token": token}
body = {"name": new_name, "description": new_descr}
response = requests.patch(
self.url + "/company/" + str(new_id),
headers=headers,
json=body
)
return response.json()
@allure.step("api. Удалить компанию '{id}'")
def delete(self, id):
token = self.get_token()
headers = {"x-client-token": token}
response = requests.delete(
self.url + "/company/" + str(id),
headers=headers
)
return response.json()
@allure.step("api. (Де)активировать компанию '{id}', isActive='{isActive}'")
def set_active_status(self, id, isActive):
token = self.get_token()
headers = {"x-client-token": token}
body = {"isActive": isActive}
response = requests.patch(
self.url + "/company/" + str(id),
headers=headers,
json=body
)
return response.json()
Пример 2 — Класс CompanyTable с @allure.step и вложениями
# db/company_table.py
import allure
from sqlalchemy import create_engine
from sqlalchemy.sql import text
class CompanyTable:
__scripts = {
"select": "select * from company",
"select_active": 'select * from company where "is_active" = true',
"delete_by_id": text("delete from company where id = :id_to_delete"),
"insert_new": text("insert into company (name) values (:new_name)"),
"select_max_id": "select max(id) from company",
}
def __init__(self, connection_string):
self.__db = create_engine(connection_string).connect()
@allure.step("БД. Запросить список организаций")
def get_companies(self):
query = self.__db.execute(self.__scripts["select"])
allure.attach(
str(query.context.cursor.query),
"SQL-запрос на получение списка компаний",
allure.attachment_type.TEXT
)
return query.fetchall()
@allure.step("БД. Запросить список активных организаций")
def get_active_companies(self):
query = self.__db.execute(self.__scripts["select_active"])
allure.attach(
str(query.context.cursor.query),
"SQL-запрос на получение активных компаний",
allure.attachment_type.TEXT
)
return query.fetchall()
@allure.step("БД. Запросить организацию по {id}")
def get_company_by_id(self, id):
query = self.__db.execute(
text("select * from company where id = :cid"),
{"cid": id}
)
allure.attach(
str(query.context.cursor.query),
"SQL-запрос на получение компании по id",
allure.attachment_type.TEXT
)
return query.fetchone()
@allure.step("БД. Удалить организацию по {id}")
def delete(self, id):
params = {"id_to_delete": id}
query = self.__db.execute(self.__scripts["delete_by_id"], parameters=params)
allure.attach(
str(query.context.cursor.query),
"SQL-запрос на удаление компании",
allure.attachment_type.TEXT
)
@allure.step("БД. Создать организацию с названием {name}")
def create(self, name):
params = {"new_name": name}
query = self.__db.execute(self.__scripts["insert_new"], parameters=params)
allure.attach(
str(query.context.cursor.query),
"SQL-запрос на создание компании",
allure.attachment_type.TEXT
)
@allure.step("БД. Получить максимальный id организации")
def get_max_id(self):
query = self.__db.execute(self.__scripts["select_max_id"])
allure.attach(
str(query.context.cursor.query),
"SQL-запрос на получение максимального id",
allure.attachment_type.TEXT
)
return query.fetchone()[0]
Пример 3 — Тесты с разметкой Allure и шагами
# tests/test_x_clients_db.py
import allure
from api.company_api import CompanyApi
from db.company_table import CompanyTable
@allure.epic("компании")
@allure.severity("blocker")
class CompanyTest:
api = CompanyApi("https://x-clients-be.onrender.com")
db = CompanyTable(
"postgresql://x_clients_user:password@host/x_clients_db"
)
# --- Тест 1: Получение полного списка компаний ---
@allure.id("ITCH-1")
@allure.story("Получение списка компаний")
@allure.feature("READ")
@allure.title("Получение полного списка организаций")
def test_get_companies(self):
api_result = self.api.get_company_list() # → шаг "api. Получить список компаний"
db_result = self.db.get_companies() # → шаг "БД. Запросить список организаций"
assert len(api_result) == len(db_result)
# --- Тест 2: Только активные компании ---
@allure.id("ITCH-2")
@allure.story("Получение списка компаний")
@allure.feature("READ")
@allure.title("Получение списка активных организаций")
@allure.description("Запрос организаций с параметром active = true")
def test_get_active_companies(self):
api_result = self.api.get_company_list(params_to_add={"active": True})
db_result = self.db.get_active_companies()
assert len(api_result) == len(db_result)
# --- Тест 3: Создание компании (вложенные шаги) ---
@allure.id("ITCH-3")
@allure.story("Создание компаний")
@allure.feature("CREATE")
@allure.title("Создание организации")
def test_add_new(self):
with allure.step("Получить количество организаций ДО"):
body = self.api.get_company_list()
len_before = len(body)
with allure.step("Создать организацию"):
with allure.step("Сгенерировать название"):
name = "Autotest"
descr = "Autotest description"
with allure.step("Вызвать API-метод для создания"):
result = self.api.create_company(name, descr)
new_id = result["id"]
with allure.step("Проверить поля новой организации"):
body = self.api.get_company_list()
found = next((c for c in body if c["id"] == new_id), None)
assert found is not None
assert found["name"] == name
assert found["description"] == descr
with allure.step("Получить количество организаций ПОСЛЕ"):
body = self.api.get_company_list()
len_after = len(body)
with allure.step("Проверить, что список ДО меньше списка ПОСЛЕ на 1"):
assert len_after - len_before == 1
with allure.step("Удалить из БД новую организацию"):
self.db.delete(new_id)
# --- Тест 4: Получение компании по id ---
@allure.id("ITCH-4")
@allure.story("Получение компании по id")
@allure.feature("READ")
@allure.title("Получение организации по id")
def test_get_one_company(self):
body = self.api.get_company_list()
cid = body[0]["id"]
result = self.api.get_company(cid)
assert result["id"] == cid
Пример 4 — Базовая аннотация + шаг (минимальный пример)
# tests/test_login.py
import allure
@allure.feature("Авторизация")
@allure.story("Успешный вход пользователя")
def test_user_login():
with allure.step("Открытие страницы авторизации"):
pass # здесь: driver.get(url) или requests.get(url)
with allure.step("Ввод логина и пароля"):
pass # здесь: отправка credentials
with allure.step("Проверка успешного входа в систему"):
assert True # здесь: assert response.status_code == 200
Пример 5 — Вложение лога выполнения
# tests/test_attachment_demo.py
import allure
def test_with_text_attachment():
log = "Запрос: GET /company\nОтвет: 200 OK\nДанных: 5 записей"
allure.attach(log, name="Лог выполнения теста",
attachment_type=allure.attachment_type.TEXT)
assert True