Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
venv/
__pycache__/
.pytest_cache/
*.pyc
allure-results/
allure-report/
.coverage
htmlcov/
.idea/
.vscode/
.DS_Store
Thumbs.db
73 changes: 73 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,74 @@
# Diplom_2
API-тесты Stellar Burgers
Описание

В проекте реализованы автоматизированные тесты API сервиса Stellar Burgers.

Тестирование выполняется с использованием:
pytest
requests
allure-pytest

Отчёт формируется в Allure.

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

Создание уникального пользователя
Создание пользователя, который уже зарегистрирован
Создание пользователя без одного из обязательных полей

Логин пользователя

Вход под существующим пользователем
Вход с неверным логином и паролем

Создание заказа

Создание заказа с авторизацией
Создание заказа без авторизации
Создание заказа с ингредиентами
Создание заказа без ингредиентов
Создание заказа с неверным хешем ингредиентов

Структура проекта
Diplom_2
├── src
│ ├── api.py
│ ├── config.py
│ └── helpers.py
├── tests
│ ├── conftest.py
│ ├── test_create_user.py
│ ├── test_login.py
│ └── test_orders.py
├── pytest.ini
├── requirements.txt
├── .gitignore
└── README.md

Установка зависимостей

python -m venv venv
source venv/Scripts/activate
pip install -r requirements.txt

Запуск тестов
pytest

Формирование отчёта Allure

Сбор результатов
pytest --alluredir=allure-results

Просмотр отчёта (если установлен Allure CLI)
allure serve allure-results

Или создание HTML-отчёта:

allure generate allure-results -o allure-report --clean

Результат

Все тесты проходят успешно.
Результаты выполнения тестов отображаются в отчёте Allure.
4 changes: 4 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[pytest]
testpaths = tests
pythonpath = .
addopts = -v
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pytest
requests
allure-pytest
44 changes: 44 additions & 0 deletions src/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import allure
import requests

from src.config import BASE_URL, REGISTER, LOGIN, INGREDIENTS, ORDERS, USER


class StellarApi:
def __init__(self):
self.session = requests.Session()

@allure.step("POST {path}")
def post(self, path: str, json: dict | None = None, headers: dict | None = None):
return self.session.post(BASE_URL + path, json=json, headers=headers)

@allure.step("GET {path}")
def get(self, path: str, headers: dict | None = None):
return self.session.get(BASE_URL + path, headers=headers)

@allure.step("DELETE {path}")
def delete(self, path: str, headers: dict | None = None):
return self.session.delete(BASE_URL + path, headers=headers)

@allure.step("Зарегистрировать пользователя")
def register(self, payload: dict):
return self.post(REGISTER, json=payload)

@allure.step("Выполнить логин пользователя")
def login(self, payload: dict):
return self.post(LOGIN, json=payload)

@allure.step("Получить список ингредиентов")
def get_ingredients(self):
return self.get(INGREDIENTS)

@allure.step("Создать заказ")
def create_order(self, ingredients: list[str] | None = None, token: str | None = None):
headers = {"Authorization": token} if token else None
body = {"ingredients": ingredients} if ingredients is not None else {}
return self.post(ORDERS, json=body, headers=headers)

@allure.step("Удалить пользователя")
def delete_user(self, token: str):
headers = {"Authorization": token}
return self.delete(USER, headers=headers)
7 changes: 7 additions & 0 deletions src/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
BASE_URL = "https://stellarburgers.education-services.ru/api"

REGISTER = "/auth/register"
LOGIN = "/auth/login"
INGREDIENTS = "/ingredients"
ORDERS = "/orders"
USER = "/auth/user"
15 changes: 15 additions & 0 deletions src/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import random
import string


def rand_str(n: int = 10) -> str:
chars = string.ascii_letters + string.digits
return "".join(random.choice(chars) for _ in range(n))


def generate_user() -> dict:
return {
"email": f"eva_{rand_str(8).lower()}@yandex.ru",
"password": rand_str(12),
"name": f"Eva_{rand_str(6)}",
}
81 changes: 81 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import pytest
import allure

from src.helpers import generate_user
from src.api import StellarApi


@pytest.fixture
def api():
return StellarApi()


@pytest.fixture
def cleanup_user(api):
tokens = []

yield tokens

for token in tokens:
with allure.step("Удаляем пользователя после теста"):
api.delete_user(token)


@pytest.fixture
def registered_user(api, cleanup_user):
user = generate_user()

with allure.step("Регистрируем пользователя для предусловия теста"):
response = api.register(user)

access_token = None
if response.status_code == 200:
body = response.json()
access_token = body.get("accessToken")
cleanup_user.append(access_token)

return {
"email": user["email"],
"password": user["password"],
"name": user["name"],
"response": response,
"access_token": access_token,
}


@pytest.fixture
def token(api, registered_user):
with allure.step("Логинимся и получаем токен"):
response = api.login(
{
"email": registered_user["email"],
"password": registered_user["password"],
}
)

access_token = None
if response.status_code == 200:
body = response.json()
access_token = body.get("accessToken")

return {
"response": response,
"access_token": access_token,
}


@pytest.fixture
def ingredient_ids(api):
with allure.step("Получаем список ингредиентов"):
response = api.get_ingredients()

ids = []
if response.status_code == 200:
body = response.json()
data = body.get("data", [])
ids = [item["_id"] for item in data]

return {
"response": response,
"ids": ids,
}
64 changes: 64 additions & 0 deletions tests/test_create_user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import allure

from src.helpers import generate_user


@allure.epic("Создание пользователя")
class TestCreateUser:

@allure.title("Можно создать уникального пользователя")
def test_create_unique_user_success(self, api, cleanup_user):
user = generate_user()

with allure.step("Регистрируем уникального пользователя"):
response = api.register(user)

body = response.json()

if response.status_code == 200 and "accessToken" in body:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Можно лучше: чтобы не создавать ветвление в тесте оптимально было бы чистить БД фикстурой после проверки, в постусловии

cleanup_user.append(body["accessToken"])

assert response.status_code == 200
assert body.get("success") is True
assert "accessToken" in body
assert "refreshToken" in body
assert body["user"]["email"] == user["email"]
assert body["user"]["name"] == user["name"]

@allure.title("Нельзя создать двух одинаковых пользователей")
def test_create_duplicate_user_returns_error(self, api, cleanup_user):
user = generate_user()

with allure.step("Регистрируем пользователя впервые"):
first_response = api.register(user)

first_body = first_response.json()

if first_response.status_code == 200 and "accessToken" in first_body:
cleanup_user.append(first_body["accessToken"])

with allure.step("Повторно отправляем запрос на регистрацию того же пользователя"):
response = api.register(user)

body = response.json()

assert response.status_code == 403
assert body.get("success") is False
assert body.get("message") == "User already exists"

@allure.title("Нельзя создать пользователя без обязательного поля")
def test_create_user_without_required_field_returns_error(self, api, cleanup_user):
user = generate_user()
user.pop("name")

with allure.step("Отправляем запрос на регистрацию без поля name"):
response = api.register(user)

body = response.json()

if response.status_code == 200 and "accessToken" in body:
cleanup_user.append(body["accessToken"])

assert response.status_code == 403
assert body.get("success") is False
assert body.get("message") == "Email, password and name are required fields"
37 changes: 37 additions & 0 deletions tests/test_login.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import allure


@allure.feature("Логин пользователя")
class TestLogin:

@allure.title("Вход под существующим пользователем")
def test_login_existing_user(self, api, registered_user):
with allure.step("Логинимся под существующим пользователем"):
response = api.login(
{
"email": registered_user["email"],
"password": registered_user["password"],
}
)

body = response.json()

assert response.status_code == 200
assert body.get("success") is True
assert "accessToken" in body
assert "refreshToken" in body

@allure.title("Вход с неверным логином и паролем")
def test_login_wrong_credentials(self, api):
with allure.step("Логинимся с неверными данными"):
response = api.login(
{
"email": "nope@yandex.ru",
"password": "wrong",
}
)

body = response.json()

assert response.status_code == 401
assert body.get("success") is False
Loading