diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..e4149ff4b --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.idea/ +.venv/ +.vscode/ +__pycache__/ +.coverage diff --git a/README.md b/README.md index 272081708..742b0f25c 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,34 @@ -## Задание 1: Юнит-тесты +# Задание 1: Юнит-тесты -### Автотесты для проверки программы, которая помогает заказать бургер в Stellar Burgers +--- -### Реализованные сценарии +## Описание: + +Автотесты для проверки программы, которая помогает заказать бургер в Stellar Burgers + +--- + +## Реализованные сценарии Созданы юнит-тесты, покрывающие классы `Bun`, `Burger`, `Ingredient`, `Database` Процент покрытия 100% (отчет: `htmlcov/index.html`) -### Структура проекта +--- + +## Структура проекта - `praktikum` - пакет, содержащий код программы - `tests` - пакет, содержащий тесты, разделенные по классам. Например, `bun_test.py`, `burger_test.py` и т.д. -### Запуск автотестов +--- + +## Запуск автотестов **Установка зависимостей** -> `$ pip install -r requirements.txt` +> `pip install -r requirements.txt` **Запуск автотестов и создание HTML-отчета о покрытии** -> `$ pytest --cov=praktikum --cov-report=html` +> `pytest --cov=praktikum --cov-report=html` diff --git a/core/__init__.py b/core/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/core/utils/__init__.py b/core/utils/__init__.py new file mode 100644 index 000000000..5c8104d4d --- /dev/null +++ b/core/utils/__init__.py @@ -0,0 +1,4 @@ +from .create_fake_bun import get_bun_mock +from .create_fake_ingredient import get_ingredient_mock + +__all__ = ["get_ingredient_mock", "get_bun_mock"] diff --git a/core/utils/create_fake_bun.py b/core/utils/create_fake_bun.py new file mode 100644 index 000000000..5591ea8a4 --- /dev/null +++ b/core/utils/create_fake_bun.py @@ -0,0 +1,16 @@ +import uuid +from unittest.mock import Mock + + +def get_bun_mock() -> Mock: + mock = Mock() + + mock.get_name.return_value = f"fake_bun_{uuid.uuid4()}" + mock.get_price.return_value = 1 + mock.get_type.return_value = "fake_bun_type" + + return mock + + +if __name__ == "__main__": + print(uuid.uuid4()) diff --git a/core/utils/create_fake_ingredient.py b/core/utils/create_fake_ingredient.py new file mode 100644 index 000000000..83255c971 --- /dev/null +++ b/core/utils/create_fake_ingredient.py @@ -0,0 +1,12 @@ +import uuid +from unittest.mock import Mock + + +def get_ingredient_mock() -> Mock: + mock = Mock() + + mock.get_name.return_value = f"fake_ingredient_{uuid.uuid4()}" + mock.get_price.return_value = 1 + mock.get_type.return_value = "fake_ingredient_type" + + return mock diff --git a/praktikum.py b/praktikum.py deleted file mode 100644 index ec522fa6d..000000000 --- a/praktikum.py +++ /dev/null @@ -1,41 +0,0 @@ -from typing import List - -from praktikum.bun import Bun -from praktikum.burger import Burger -from praktikum.database import Database -from praktikum.ingredient import Ingredient - - -def main(): - # Инициализируем базу данных - database: Database = Database() - - # Создадим новый бургер - burger: Burger = Burger() - - # Считаем список доступных булок из базы данных - buns: List[Bun] = database.available_buns() - - # Считаем список доступных ингредиентов из базы данных - ingredients: List[Ingredient] = database.available_ingredients() - - # Соберём бургер - burger.set_buns(buns[0]) - - burger.add_ingredient(ingredients[1]) - burger.add_ingredient(ingredients[4]) - burger.add_ingredient(ingredients[3]) - burger.add_ingredient(ingredients[5]) - - # Переместим слой с ингредиентом - burger.move_ingredient(2, 1) - - # Удалим ингредиент - burger.remove_ingredient(3) - - # Распечатаем рецепт бургера - print(burger.get_receipt()) - - -if __name__ == "__main__": - main() diff --git a/praktikum/__init__.py b/praktikum/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/bun.py b/praktikum/bun.py similarity index 100% rename from bun.py rename to praktikum/bun.py diff --git a/burger.py b/praktikum/burger.py similarity index 95% rename from burger.py rename to praktikum/burger.py index 2b3b6a88b..a33cc7c4f 100644 --- a/burger.py +++ b/praktikum/burger.py @@ -1,7 +1,7 @@ from typing import List -from praktikum.bun import Bun -from praktikum.ingredient import Ingredient +from .bun import Bun +from .ingredient import Ingredient class Burger: diff --git a/database.py b/praktikum/database.py similarity index 86% rename from database.py rename to praktikum/database.py index 4c75baf71..b99c35512 100644 --- a/database.py +++ b/praktikum/database.py @@ -1,8 +1,8 @@ from typing import List -from praktikum.bun import Bun -from praktikum.ingredient import Ingredient -from praktikum.ingredient_types import INGREDIENT_TYPE_SAUCE, INGREDIENT_TYPE_FILLING +from .bun import Bun +from .ingredient import Ingredient +from .ingredient_types import INGREDIENT_TYPE_SAUCE, INGREDIENT_TYPE_FILLING class Database: diff --git a/ingredient.py b/praktikum/ingredient.py similarity index 100% rename from ingredient.py rename to praktikum/ingredient.py diff --git a/ingredient_types.py b/praktikum/ingredient_types.py similarity index 100% rename from ingredient_types.py rename to praktikum/ingredient_types.py diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 000000000..eae7d339a --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +allure-pytest==2.15.0 +pytest==8.4.2 +pytest-cov==7.0.0 diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 000000000..6f8dbebb3 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,46 @@ +from typing import Callable +from unittest.mock import Mock + +import pytest + +from praktikum.bun import Bun +from praktikum.ingredient import Ingredient +from praktikum.ingredient_types import * +from core.utils import get_bun_mock, get_ingredient_mock + + +@pytest.fixture +def get_fake_bun() -> Callable: + def _inner(count: int = 1) -> list[Mock]: + return [get_bun_mock() for _ in range(count)] + + return _inner + + +@pytest.fixture +def get_fake_ingredient() -> Callable: + def _inner(count: int = 1) -> list[Mock]: + return [get_ingredient_mock() for _ in range(count)] + + return _inner + + +@pytest.fixture +def get_buns_from_db() -> list[Bun]: + return [ + Bun("black bun", 100), + Bun("white bun", 200), + Bun("red bun", 300), + ] + + +@pytest.fixture +def get_ingredients_from_db() -> list[Ingredient]: + return [ + Ingredient(INGREDIENT_TYPE_SAUCE, "hot sauce", 100), + Ingredient(INGREDIENT_TYPE_SAUCE, "sour cream", 200), + Ingredient(INGREDIENT_TYPE_SAUCE, "chili sauce", 300), + Ingredient(INGREDIENT_TYPE_FILLING, "cutlet", 100), + Ingredient(INGREDIENT_TYPE_FILLING, "dinosaur", 200), + Ingredient(INGREDIENT_TYPE_FILLING, "sausage", 300), + ] diff --git a/tests/test_bun.py b/tests/test_bun.py new file mode 100644 index 000000000..9fcfcfdbe --- /dev/null +++ b/tests/test_bun.py @@ -0,0 +1,20 @@ +import pytest + +from praktikum.bun import Bun + + +class TestBun: + + @pytest.mark.parametrize("name", ["Бриошь", "Рисовая", " ", ""]) + def test_return_correct_name_when_bun_is_created(self, name): + bun = Bun(name, 1.5) + + assert bun.get_name() == name + assert bun.name == name + + @pytest.mark.parametrize("price", [5, -5, 0.0, 1.5]) + def test_return_correct_price_when_bun_is_created(self, price): + bun = Bun("fake_bun", price) + + assert bun.get_price() == price + assert bun.price == price diff --git a/tests/test_burger.py b/tests/test_burger.py new file mode 100644 index 000000000..f1aad3f48 --- /dev/null +++ b/tests/test_burger.py @@ -0,0 +1,87 @@ +from praktikum.burger import Burger + + +class TestBurger: + + def test_set_correct_bun_when_burger_is_created(self, get_fake_bun): + burger = Burger() + fake_bun, *_ = get_fake_bun() + + burger.set_buns(fake_bun) + assert burger.bun.get_name() == fake_bun.get_name() + + def test_add_ingredient_to_burger(self, get_fake_ingredient): + burger = Burger() + ingredient, *_ = get_fake_ingredient() + + burger.add_ingredient(ingredient) + assert burger.ingredients[0] == ingredient + + def test_add_multiple_ingredients_to_burger(self, get_fake_ingredient): + burger = Burger() + ingredient, *_ = get_fake_ingredient() + n = 5 + + for _ in range(n): + burger.add_ingredient(ingredient) + + assert len(burger.ingredients) == n + + def test_remove_ingredient_from_burger(self, get_fake_ingredient): + burger = Burger() + ingredient, *_ = get_fake_ingredient() + + burger.add_ingredient(ingredient) + burger.remove_ingredient(0) + + assert len(burger.ingredients) == 0 + + def test_swap_ingredient_in_burger(self, get_fake_ingredient): + burger = Burger() + n = 3 + + first, second, third = get_fake_ingredient(n) + + burger.add_ingredient(first) + burger.add_ingredient(second) + burger.add_ingredient(third) + + burger.move_ingredient(1, 2) + + assert burger.ingredients == [first, third, second] + + def test_return_correct_price_when_burger_is_created(self, get_fake_bun, get_fake_ingredient): + burger = Burger() + n = 3 + price = 5 + fake_bun, *_ = get_fake_bun() + + burger.set_buns(fake_bun) + first, second, third = get_fake_ingredient(n) + + burger.add_ingredient(first) + burger.add_ingredient(second) + burger.add_ingredient(third) + + assert burger.get_price() == price + + def test_return_correct_receipt_when_burger_is_created(self, get_fake_bun, get_fake_ingredient): + burger = Burger() + n = 3 + fake_bun, *_ = get_fake_bun() + + burger.set_buns(fake_bun) + first, second, third = get_fake_ingredient(n) + + burger.add_ingredient(first) + burger.add_ingredient(second) + burger.add_ingredient(third) + + assert burger.get_receipt() == ( + f"(==== {fake_bun.get_name()} ====)\n" + f"= {first.get_type()} {first.get_name()} =\n" + f"= {second.get_type()} {second.get_name()} =\n" + f"= {third.get_type()} {third.get_name()} =\n" + f"(==== {fake_bun.get_name()} ====)\n\n" + "Price: 5" + ) diff --git a/tests/test_database.py b/tests/test_database.py new file mode 100644 index 000000000..1ecc7e110 --- /dev/null +++ b/tests/test_database.py @@ -0,0 +1,24 @@ +from praktikum.database import Database + + +class TestDatabase: + + def test_return_correct_buns_from_db(self, get_buns_from_db): + db = Database() + available_buns = db.available_buns() + n = 3 + + assert len(available_buns) == n + + for available_bun, bun_from_db in zip(available_buns, get_buns_from_db): + assert available_bun.get_name() == bun_from_db.get_name() + + def test_return_correct_ingredients_from_db(self, get_ingredients_from_db): + db = Database() + available_ingredients = db.available_ingredients() + n = 6 + + assert len(available_ingredients) == n + + for available_ingredient, ingredient_from_db in zip(available_ingredients, get_ingredients_from_db): + assert available_ingredient.get_name() == ingredient_from_db.get_name() diff --git a/tests/test_ingredients.py b/tests/test_ingredients.py new file mode 100644 index 000000000..dcf7b5703 --- /dev/null +++ b/tests/test_ingredients.py @@ -0,0 +1,27 @@ +import pytest + +from praktikum.ingredient import Ingredient + + +class TestIngredient: + + @pytest.mark.parametrize("name", ["чесночный", "кетчуп", ""]) + def test_return_correct_name_when_ingredient_is_created(self, name): + ingredient = Ingredient("соус", name, 1.0) + + assert ingredient.get_name() == name + assert ingredient.name == name + + @pytest.mark.parametrize("curr_type", ["соус", "начинка", ""]) + def test_return_correct_type_when_ingredient_is_created(self, curr_type): + ingredient = Ingredient(curr_type, "fake_ingredient", 1.5) + + assert ingredient.get_type() == curr_type + assert ingredient.type == curr_type + + @pytest.mark.parametrize("price", [5, -5, 0.0, 1.5]) + def test_return_correct_price_when_ingredient_is_created(self, price): + ingredient = Ingredient("fake_type", "fake_ingredient", price) + + assert ingredient.get_price() == price + assert ingredient.price == price