diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..85bd9dfec --- /dev/null +++ b/.gitignore @@ -0,0 +1,46 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +env/ +venv/ +ENV/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# Testing +.pytest_cache/ +.coverage +htmlcov/ +.tox/ +.allure/ +allure-results/ +allure-report/ + +# IDE +.vscode/ +.idea/ +*.iml + +# OS +.DS_Store +Thumbs.db + +# Logs +*.log \ No newline at end of file diff --git a/conftest.py b/conftest.py new file mode 100644 index 000000000..a742b72f0 --- /dev/null +++ b/conftest.py @@ -0,0 +1,37 @@ +import pytest +from unittest.mock import Mock + +from praktikum.burger import Burger +from praktikum.database import Database +from praktikum.bun import Bun +from praktikum.ingredient import Ingredient +from praktikum.ingredient_types import INGREDIENT_TYPE_SAUCE, INGREDIENT_TYPE_FILLING + + +@pytest.fixture +def db(): + db = Database() + return db + +@pytest.fixture +def burger(): + burger = Burger() + return burger + +@pytest.fixture +def mock_bun(): + bun = Mock(spec=Bun) + bun.get_name.return_value = "test bun" + bun.get_price.return_value = 100.0 + return bun + +@pytest.fixture +def mock_ingredients(): + ingredients = [] + for i in range(3): + ingredient = Mock(spec=Ingredient) + ingredient.get_name.return_value = f"ingredient_{i}" + ingredient.get_price.return_value = float(50 * (i + 1)) + ingredient.get_type.return_value = INGREDIENT_TYPE_SAUCE if i % 2 == 0 else INGREDIENT_TYPE_FILLING + ingredients.append(ingredient) + return ingredients \ No newline at end of file diff --git a/data.py b/data.py new file mode 100644 index 000000000..dec7588e5 --- /dev/null +++ b/data.py @@ -0,0 +1,15 @@ +class BunTestData: + + VALID_BUN = {"name": "classic bun", "price": 111.0} + + + MIN_PRICE_BUN = {"name": "min price bun", "price": 0.0} + MAX_PRICE_BUN = {"name": "max price bun", "price": 1000000.0} + + + EMPTY_NAME_BUN = {"name": "", "price": 100.0} + NEGATIVE_PRICE_BUN = {"name": "negative price", "price": -50.0} + + @staticmethod + def get_valid_bun(): + return BunTestData.VALID_BUN.copy() \ No newline at end of file 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 59% rename from bun.py rename to praktikum/bun.py index 5504bc1f4..95fda02de 100644 --- a/bun.py +++ b/praktikum/bun.py @@ -1,8 +1,4 @@ class Bun: - """ - Модель булочки для бургера. - Булочке можно дать название и назначить цену. - """ def __init__(self, name: str, price: float): self.name = name diff --git a/burger.py b/praktikum/burger.py similarity index 100% rename from burger.py rename to praktikum/burger.py diff --git a/database.py b/praktikum/database.py similarity index 100% rename from database.py rename to praktikum/database.py 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/praktikum.py b/praktikum/praktikum.py similarity index 100% rename from praktikum.py rename to praktikum/praktikum.py diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 000000000..e69de29bb diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/test_bun.py b/tests/test_bun.py new file mode 100644 index 000000000..d02aeb721 --- /dev/null +++ b/tests/test_bun.py @@ -0,0 +1,26 @@ +import pytest +from praktikum.bun import Bun +from data import BunTestData + + +class TestBun: + + @pytest.mark.parametrize("bun_data", [ + BunTestData.VALID_BUN, + BunTestData.VALID_BUN_2, + BunTestData.EMPTY_NAME_BUN, + ]) + def test_bun_creation(self, bun_data): + bun = Bun(bun_data["name"], bun_data["price"]) + assert bun.get_name() == bun_data["name"] + assert bun.get_price() == bun_data["price"] + + def test_bun_get_name(self): + bun_data = BunTestData.VALID_BUN + bun = Bun(bun_data['name'], bun_data['price']) + assert bun.get_name() == bun_data['name'] + + def test_bun_get_price(self): + bun_data = BunTestData.VALID_BUN_2 + bun = Bun(bun_data['name'], bun_data['price']) + assert bun.get_price() == bun_data['price'] \ No newline at end of file diff --git a/tests/test_burger.py b/tests/test_burger.py new file mode 100644 index 000000000..64f11225e --- /dev/null +++ b/tests/test_burger.py @@ -0,0 +1,116 @@ +import pytest +from unittest.mock import Mock +from praktikum.bun import Bun +from praktikum.ingredient import Ingredient + + +class TestBurger: + + def test_burger_initialization(self, burger): + """Тест проверяет, что бургер создается с пустыми ингредиентами и без булки""" + assert burger.bun is None + assert burger.ingredients == [] + + def test_set_buns(self, burger, mock_bun): + """Тест проверяет установку булки в бургер""" + burger.set_buns(mock_bun) + assert burger.bun == mock_bun + + def test_add_ingredient(self, burger, mock_ingredients): + """Тест проверяет добавление одного ингредиента в бургер""" + burger.add_ingredient(mock_ingredients[0]) + assert len(burger.ingredients) == 1 + assert burger.ingredients[0] == mock_ingredients[0] + + def test_add_multiple_ingredients(self, burger, mock_ingredients): + """Тест проверяет добавление нескольких ингредиентов в бургер""" + for ingredient in mock_ingredients: + burger.add_ingredient(ingredient) + assert len(burger.ingredients) == len(mock_ingredients) + assert burger.ingredients == mock_ingredients + + def test_remove_ingredient(self, burger, mock_ingredients): + """Тест проверяет удаление ингредиента из бургера""" + for ingredient in mock_ingredients: + burger.add_ingredient(ingredient) + + burger.remove_ingredient(1) + assert len(burger.ingredients) == 2 + assert burger.ingredients[0] == mock_ingredients[0] + assert burger.ingredients[1] == mock_ingredients[2] + + def test_move_ingredient_forward(self, burger, mock_ingredients): + """Тест проверяет перемещение ингредиента вперед""" + for ingredient in mock_ingredients: + burger.add_ingredient(ingredient) + + burger.move_ingredient(2, 0) + assert burger.ingredients[0] == mock_ingredients[2] + assert burger.ingredients[1] == mock_ingredients[0] + assert burger.ingredients[2] == mock_ingredients[1] + + def test_move_ingredient_backward(self, burger, mock_ingredients): + """Тест проверяет перемещение ингредиента назад""" + for ingredient in mock_ingredients: + burger.add_ingredient(ingredient) + + burger.move_ingredient(0, 2) + assert burger.ingredients[0] == mock_ingredients[1] + assert burger.ingredients[1] == mock_ingredients[2] + assert burger.ingredients[2] == mock_ingredients[0] + + def test_get_price_with_bun_no_ingredients(self, burger, mock_bun): + """Тест проверяет расчет цены бургера только с булкой""" + burger.set_buns(mock_bun) + price = burger.get_price() + assert price == 200.0 + mock_bun.get_price.assert_called_once() + + def test_get_price_with_bun_and_ingredients(self, burger, mock_bun, mock_ingredients): + """Тест проверяет расчет цены бургера с булкой и ингредиентами""" + burger.set_buns(mock_bun) + for ingredient in mock_ingredients: + burger.add_ingredient(ingredient) + + expected_price = 200.0 + 50 + 100 + 150 + assert burger.get_price() == expected_price + + mock_bun.get_price.assert_called_once() + for ingredient in mock_ingredients: + ingredient.get_price.assert_called_once() + + @pytest.mark.parametrize("bun_price, ingredient_prices, expected_price", [ + (100, [50, 75], 100*2 + 50 + 75), + (200, [100, 150, 200], 200*2 + 100 + 150 + 200), + (150, [], 150*2), + (0, [50, 50], 0*2 + 50 + 50), + ]) + def test_get_price_parametrized(self, burger, bun_price, ingredient_prices, expected_price): + """Параметризованный тест проверяет расчет цены с разными данными""" + mock_bun = Mock(spec=Bun) + mock_bun.get_price.return_value = float(bun_price) + burger.set_buns(mock_bun) + + for price in ingredient_prices: + mock_ingredient = Mock(spec=Ingredient) + mock_ingredient.get_price.return_value = float(price) + burger.add_ingredient(mock_ingredient) + + assert burger.get_price() == expected_price + + def test_get_price_without_bun(self, burger, mock_ingredients): + """Тест проверяет расчет цены без булки""" + for ingredient in mock_ingredients: + burger.add_ingredient(ingredient) + + assert burger.get_price() == 50 + 100 + 150 + + def test_clear_ingredients(self, burger, mock_ingredients): + """Тест проверяет очистку ингредиентов""" + for ingredient in mock_ingredients: + burger.add_ingredient(ingredient) + + assert len(burger.ingredients) == 3 + + burger.ingredients.clear() + assert len(burger.ingredients) == 0 \ No newline at end of file diff --git a/tests/test_database.py b/tests/test_database.py new file mode 100644 index 000000000..a83a260f6 --- /dev/null +++ b/tests/test_database.py @@ -0,0 +1,57 @@ +import pytest +from praktikum.bun import Bun +from praktikum.ingredient import Ingredient +from praktikum.ingredient_types import INGREDIENT_TYPE_SAUCE, INGREDIENT_TYPE_FILLING +from data import BunTestData, IngredientTestData + + +class TestDatabase: + + def test_database_initialization(self, db): + + assert len(db.buns) == 3 + assert len(db.ingredients) == 6 + + def test_available_buns(self, db): + + buns = db.available_buns() + + assert len(buns) == 3 + assert all(isinstance(bun, Bun) for bun in buns) + + + for bun in buns: + assert bun.get_name() is not None + assert bun.get_price() is not None + + def test_available_ingredients(self, db): + + ingredients = db.available_ingredients() + + assert len(ingredients) == 6 + assert all(isinstance(ingredient, Ingredient) for ingredient in ingredients) + + + sauces = [i for i in ingredients if i.get_type() == INGREDIENT_TYPE_SAUCE] + assert len(sauces) == 3 + for sauce in sauces: + assert sauce.get_name() is not None + assert sauce.get_price() is not None + + fillings = [i for i in ingredients if i.get_type() == INGREDIENT_TYPE_FILLING] + assert len(fillings) == 3 + for filling in fillings: + assert filling.get_name() is not None + assert filling.get_price() is not None + + def test_database_buns_are_different_objects(self, db): + + buns = db.available_buns() + assert buns[0] is not buns[1] + assert buns[1] is not buns[2] + + def test_database_ingredients_are_different_objects(self, db): + + ingredients = db.available_ingredients() + for i in range(len(ingredients) - 1): + assert ingredients[i] is not ingredients[i + 1] \ No newline at end of file diff --git a/tests/test_ingredients.py b/tests/test_ingredients.py new file mode 100644 index 000000000..f6f4f21a0 --- /dev/null +++ b/tests/test_ingredients.py @@ -0,0 +1,48 @@ +import pytest +from praktikum.ingredient import Ingredient +from data import IngredientTestData + + +class TestIngredient: + + @pytest.mark.parametrize("ingredient_data", [ + IngredientTestData.get_valid_sauce(), + IngredientTestData.get_valid_filling(), + IngredientTestData.get_invalid_ingredient(), + ]) + def test_ingredient_creation(self, ingredient_data): + ingredient = Ingredient( + ingredient_data["ingredient_type"], + ingredient_data["name"], + ingredient_data["price"] + ) + assert ingredient.get_type() == ingredient_data["ingredient_type"] + assert ingredient.get_name() == ingredient_data["name"] + assert ingredient.get_price() == ingredient_data["price"] + + def test_ingredient_get_type(self): + ingredient_data = IngredientTestData.get_valid_sauce() + ingredient = Ingredient( + ingredient_data['ingredient_type'], + ingredient_data['name'], + ingredient_data['price'] + ) + assert ingredient.get_type() == ingredient_data['ingredient_type'] + + def test_ingredient_get_name(self): + ingredient_data = IngredientTestData.get_valid_sauce() + ingredient = Ingredient( + ingredient_data['ingredient_type'], + ingredient_data['name'], + ingredient_data['price'] + ) + assert ingredient.get_name() == ingredient_data['name'] + + def test_ingredient_get_price(self): + ingredient_data = IngredientTestData.get_valid_filling() + ingredient = Ingredient( + ingredient_data['ingredient_type'], + ingredient_data['name'], + ingredient_data['price'] + ) + assert ingredient.get_price() == ingredient_data['price'] \ No newline at end of file