diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a6e408d --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +__pycache__/ +*.pyc +.pytest_cache/ + +allure-results/ \ No newline at end of file diff --git a/README.md b/README.md index e69de29..ddabafc 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,15 @@ +# Sprint_7 + +API-тесты для сервиса Яндекс Самокат. + +## Технологии + +- Python +- Pytest +- Requests +- Allure + +## Запуск тестов + +```bash +python -m pytest tests diff --git a/conftest.py b/conftest.py new file mode 100644 index 0000000..43b772e --- /dev/null +++ b/conftest.py @@ -0,0 +1,28 @@ +import pytest + +from helpers import generate_courier_data +from courier_methods import ( + create_courier, + login_courier, + delete_courier +) + + +@pytest.fixture +def created_courier(): + + payload = generate_courier_data() + + create_courier(payload) + + yield payload + + login_response = login_courier( + payload["login"], + payload["password"] + ) + + courier_id = login_response.json()["id"] + + delete_courier(courier_id) + \ No newline at end of file diff --git a/courier_methods.py b/courier_methods.py new file mode 100644 index 0000000..e77bc9b --- /dev/null +++ b/courier_methods.py @@ -0,0 +1,35 @@ +import allure +import requests + +from data import ( + BASE_URL, + CREATE_COURIER_PATH, + LOGIN_COURIER_PATH, + DELETE_COURIER_PATH +) + + +@allure.step("Создать курьера") +def create_courier(payload): + return requests.post( + f"{BASE_URL}{CREATE_COURIER_PATH}", + data=payload + ) + + +@allure.step("Авторизовать курьера") +def login_courier(login, password): + return requests.post( + f"{BASE_URL}{LOGIN_COURIER_PATH}", + data={ + "login": login, + "password": password + } + ) + + +@allure.step("Удалить курьера") +def delete_courier(courier_id): + return requests.delete( + f"{BASE_URL}{DELETE_COURIER_PATH}/{courier_id}" + ) diff --git a/data.py b/data.py new file mode 100644 index 0000000..68568da --- /dev/null +++ b/data.py @@ -0,0 +1,13 @@ +BASE_URL = "https://qa-scooter.praktikum-services.ru/api/v1" + +CREATE_COURIER_PATH = "/courier" +LOGIN_COURIER_PATH = "/courier/login" +DELETE_COURIER_PATH = "/courier" + +CREATE_ORDER_PATH = "/orders" +GET_ORDERS_PATH = "/orders" +CANCEL_ORDER_PATH = "/orders/cancel" + +CREATE_COURIER_ERROR = "Недостаточно данных для создания учетной записи" +LOGIN_ERROR = "Недостаточно данных для входа" +DUPLICATE_LOGIN_ERROR = "Этот логин уже используется. Попробуйте другой." diff --git a/helpers.py b/helpers.py new file mode 100644 index 0000000..50c1dc3 --- /dev/null +++ b/helpers.py @@ -0,0 +1,15 @@ +import random +import string + + +def generate_random_string(length): + letters = string.ascii_lowercase + return ''.join(random.choice(letters) for _ in range(length)) + + +def generate_courier_data(): + return { + "login": generate_random_string(10), + "password": generate_random_string(10), + "firstName": generate_random_string(10) + } diff --git a/order_methods.py b/order_methods.py new file mode 100644 index 0000000..6bf9558 --- /dev/null +++ b/order_methods.py @@ -0,0 +1,24 @@ +import allure +import requests + +from data import ( + BASE_URL, + CREATE_ORDER_PATH, + CANCEL_ORDER_PATH +) + + +@allure.step("Создать заказ") +def create_order(payload): + return requests.post( + f"{BASE_URL}{CREATE_ORDER_PATH}", + json=payload + ) + + +@allure.step("Отменить заказ") +def cancel_order(track): + return requests.put( + f"{BASE_URL}{CANCEL_ORDER_PATH}", + params={"track": track} + ) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..b71f795 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +pytest==8.2.2 +requests==2.32.3 +allure-pytest==2.13.5 diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000..4e3e78e --- /dev/null +++ b/tests/README.md @@ -0,0 +1,78 @@ +# Sprint_7 + +## Автотесты API сервиса Яндекс Самокат + +Проект содержит автоматизированные тесты API сервиса Яндекс Самокат. + +### Используемые технологии + +* Python 3.14 +* pytest +* requests +* Allure + +### Реализованные проверки + +#### Создание курьера + +* создание нового курьера; +* создание двух одинаковых курьеров; +* создание курьера без логина; +* создание курьера без пароля. + +#### Логин курьера + +* успешная авторизация; +* авторизация без логина; +* авторизация без пароля; +* авторизация с неверным паролем; +* авторизация несуществующего курьера. + +#### Создание заказа + +* заказ с цветом BLACK; +* заказ с цветом GREY; +* заказ с цветами BLACK и GREY; +* заказ без указания цвета. + +#### Получение списка заказов + +* получение списка заказов. + +### Запуск тестов + +Запуск всех тестов: + +```bash +python -m pytest tests +``` + +### Генерация Allure-отчёта + +Сформировать результаты: + +```bash +python -m pytest tests --alluredir=allure-results +``` + +Открыть отчёт: + +```bash +allure serve allure-results +``` + +### Структура проекта + +``` +Sprint_7 +├── tests +│ ├── test_create_courier.py +│ ├── test_login_courier.py +│ ├── test_create_order.py +│ └── test_get_orders.py +├── conftest.py +├── data.py +├── helpers.py +├── requirements.txt +└── README.md +``` diff --git a/tests/test_create_courier.py b/tests/test_create_courier.py new file mode 100644 index 0000000..ac5b868 --- /dev/null +++ b/tests/test_create_courier.py @@ -0,0 +1,60 @@ +import allure + +from helpers import generate_courier_data +from courier_methods import create_courier +from data import ( + CREATE_COURIER_ERROR, + DUPLICATE_LOGIN_ERROR +) + + +class TestCreateCourier: + + @allure.title("Успешное создание курьера") + def test_create_courier_success(self): + + payload = generate_courier_data() + + response = create_courier(payload) + + assert response.status_code == 201 + assert response.json() == {"ok": True} + + @allure.title("Нельзя создать двух одинаковых курьеров") + def test_create_duplicate_courier(self): + + payload = generate_courier_data() + + create_courier(payload) + + response = create_courier(payload) + + assert response.status_code == 409 + assert response.json()["message"] == DUPLICATE_LOGIN_ERROR + + @allure.title("Создание курьера без логина") + def test_create_courier_without_login(self): + + payload = { + "password": "12345", + "firstName": "Ivan" + } + + response = create_courier(payload) + + assert response.status_code == 400 + assert response.json()["message"] == CREATE_COURIER_ERROR + + @allure.title("Создание курьера без пароля") + def test_create_courier_without_password(self): + + payload = { + "login": "test_login", + "firstName": "Ivan" + } + + response = create_courier(payload) + + assert response.status_code == 400 + assert response.json()["message"] == CREATE_COURIER_ERROR + \ No newline at end of file diff --git a/tests/test_create_order.py b/tests/test_create_order.py new file mode 100644 index 0000000..43c167a --- /dev/null +++ b/tests/test_create_order.py @@ -0,0 +1,44 @@ +import allure +import pytest + +from order_methods import ( + create_order, + cancel_order +) + + +class TestCreateOrder: + + @allure.title("Создание заказа с различными вариантами цвета") + @pytest.mark.parametrize( + "color", + [ + ["BLACK"], + ["GREY"], + ["BLACK", "GREY"], + [] + ] + ) + def test_create_order(self, color): + + payload = { + "firstName": "Naruto", + "lastName": "Uzumaki", + "address": "Konoha", + "metroStation": 4, + "phone": "+79999999999", + "rentTime": 5, + "deliveryDate": "2026-06-10", + "comment": "Saske", + "color": color + } + + response = create_order(payload) + + assert response.status_code == 201 + assert "track" in response.json() + + track = response.json()["track"] + + cancel_order(track) + \ No newline at end of file diff --git a/tests/test_get_orders.py b/tests/test_get_orders.py new file mode 100644 index 0000000..25c3119 --- /dev/null +++ b/tests/test_get_orders.py @@ -0,0 +1,22 @@ +import allure +import requests + +from data import ( + BASE_URL, + GET_ORDERS_PATH +) + + +class TestGetOrders: + + @allure.title("Получение списка заказов") + def test_get_orders_returns_orders_list(self): + + response = requests.get( + f"{BASE_URL}{GET_ORDERS_PATH}" + ) + + assert response.status_code == 200 + assert "orders" in response.json() + assert isinstance(response.json()["orders"], list) + \ No newline at end of file diff --git a/tests/test_login_courier.py b/tests/test_login_courier.py new file mode 100644 index 0000000..dd745e6 --- /dev/null +++ b/tests/test_login_courier.py @@ -0,0 +1,60 @@ +import allure + +from courier_methods import login_courier +from data import LOGIN_ERROR + + +class TestLoginCourier: + + @allure.title("Курьер может авторизоваться") + def test_courier_can_login(self, created_courier): + + response = login_courier( + created_courier["login"], + created_courier["password"] + ) + + assert response.status_code == 200 + assert "id" in response.json() + + @allure.title("Авторизация без логина") + def test_login_without_login(self): + + response = login_courier( + "", + "12345" + ) + + assert response.status_code == 400 + assert response.json()["message"] == LOGIN_ERROR + + @allure.title("Авторизация без пароля") + def test_login_without_password(self): + + response = login_courier( + "test_login", + "" + ) + + assert response.status_code == 400 + + @allure.title("Авторизация с неверным паролем") + def test_login_with_wrong_password(self, created_courier): + + response = login_courier( + created_courier["login"], + "wrong_password" + ) + + assert response.status_code == 404 + + @allure.title("Авторизация несуществующего курьера") + def test_login_nonexistent_courier(self): + + response = login_courier( + "nonexistent_login", + "nonexistent_password" + ) + + assert response.status_code == 404 + \ No newline at end of file