diff --git a/conftest.py b/conftest.py new file mode 100644 index 000000000..21c54d6a0 --- /dev/null +++ b/conftest.py @@ -0,0 +1,27 @@ +import pytest +from praktikum.burger import Burger +from praktikum.database import Database +from helpers import create_mock_ingredient +from data import * + +@pytest.fixture +def burger(): + return Burger() + +@pytest.fixture +def database(): + return Database() + +@pytest.fixture +def full_burger(): + """Полностью собранный бургер.""" + burger = Burger() + bun = create_mock_ingredient("bun", TEST_BUN["name"], TEST_BUN["price"]) + sauce = create_mock_ingredient(**TEST_SAUCE) + filling = create_mock_ingredient(**TEST_FILLING_1) + + burger.set_buns(bun) + burger.add_ingredient(sauce) + burger.add_ingredient(filling) + return burger + diff --git a/data.py b/data.py new file mode 100644 index 000000000..aeb0273ac --- /dev/null +++ b/data.py @@ -0,0 +1,81 @@ +from praktikum.ingredient_types import INGREDIENT_TYPE_SAUCE, INGREDIENT_TYPE_FILLING +from praktikum.bun import Bun +from praktikum.ingredient import Ingredient + +TEST_BUN_DATA = { + "names": [ + ("black bun", "black bun"), + ("булочка", "булочка"), + ("a", "a"), + ], + "prices": [ + (300.0, 300.0), + (350.50, 350.50), + (2, 2), + ] +} + +TEST_INGREDIENT_DATA = { + "types": [ + (INGREDIENT_TYPE_SAUCE, INGREDIENT_TYPE_SAUCE), + (INGREDIENT_TYPE_FILLING, INGREDIENT_TYPE_FILLING), + ], + "names": [ + ("соус", "соус"), + ("ingredient", "ingredient"), + ], + "prices": [ + (100.0, 100.0), + (0, 0), + (350.50, 350.50), + ] +} + +TEST_BUN = { + "name": "Булочка с кунжутом", + "price": 50.0 +} +TEST_BUN_2 = { + "name": "Космическая булочка", + "price": 150.0 +} + +TEST_SAUCE = { + "type": INGREDIENT_TYPE_SAUCE, + "name": "Кетчуп", + "price": 20.0 + } +TEST_FILLING_1 = { + "type": INGREDIENT_TYPE_FILLING, + "name": "Котлета гриль", + "price": 150.0 + } + +TEST_FILLING_2 = { + "type": INGREDIENT_TYPE_FILLING, + "name": "Сыр", + "price": 80.0 + } + +RECEIPT_TEMPLATE = ( + "(==== {bun} ====)\n" + "= sauce {sauce} =\n" + "= filling {filling} =\n" + "(==== {bun} ====)\n" + "\n" + "Price: {price}" +) +EXPECTED_BUNS = [ + Bun("black bun", 100), + Bun("white bun", 200), + Bun("red bun", 300) +] + +EXPECTED_INGREDIENTS = [ + 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) +] \ No newline at end of file diff --git a/helpers.py b/helpers.py new file mode 100644 index 000000000..5eca79109 --- /dev/null +++ b/helpers.py @@ -0,0 +1,9 @@ +from unittest.mock import Mock + +def create_mock_ingredient(type, name, price): + """Вспомогательная функция для создания мок-ингредиента.""" + mock = Mock() + mock.get_type.return_value = type + mock.get_name.return_value = name + mock.get_price.return_value = price + return mock \ No newline at end of file diff --git a/__init__.py b/praktikum/__init__.py similarity index 100% rename from __init__.py rename to praktikum/__init__.py 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 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/requirements.txt b/requirements.txt new file mode 100644 index 000000000..c3362913e Binary files /dev/null and b/requirements.txt differ diff --git a/tests/test_bun.py b/tests/test_bun.py new file mode 100644 index 000000000..92b24df9b --- /dev/null +++ b/tests/test_bun.py @@ -0,0 +1,17 @@ +import pytest +from praktikum.bun import Bun +from data import TEST_BUN_DATA + +class TestBun: + + @pytest.mark.parametrize("name, expected_name", TEST_BUN_DATA["names"]) + def test_get_name_returns_correct_name(self, name, expected_name): + """Метод get_name возвращает правильное имя.""" + bun = Bun(name, 100.0) + assert bun.get_name() == expected_name + + @pytest.mark.parametrize("price, expected_price", TEST_BUN_DATA["prices"]) + def test_get_price_returns_correct_price(self, price, expected_price): + """Метод get_price возвращает правильную цену.""" + bun = Bun("Булочка", price) + assert bun.get_price() == expected_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..cd7b25a1c --- /dev/null +++ b/tests/test_burger.py @@ -0,0 +1,70 @@ +from data import * + +class TestBurger: + + def test_burger_initially_empty(self, burger): + """Бургер создаётся без булочки и ингредиентов.""" + assert burger.bun is None and burger.ingredients == [] + + def test_set_buns_stores_bun(self, burger): + """Бургер сохраняет переданную булочку.""" + bun = Bun(*TEST_BUN) + burger.set_buns(bun) + assert burger.bun == bun + + def test_set_buns_overwrites_previous_bun(self, burger): + """Повторный вызов заменяет булочку.""" + bun1 = Bun(*TEST_BUN) + bun2 = Bun(*TEST_BUN_2) + burger.set_buns(bun1) + burger.set_buns(bun2) + assert burger.bun == bun2 + + def test_add_ingredient_appends_to_list(self, burger): + """Ингредиент добавляется в конец списка.""" + ingredient1 = Ingredient(*TEST_SAUCE) + ingredient2 = Ingredient(*TEST_FILLING_1) + burger.add_ingredient(ingredient1) + burger.add_ingredient(ingredient2) + assert burger.ingredients == [ingredient1, ingredient2] + + def test_can_add_same_ingredient_multiple_times(self, burger): + """Можно добавить один и тот же ингридиент несколько раз.""" + ingredient = Ingredient(*TEST_FILLING_1) + burger.add_ingredient(ingredient) + burger.add_ingredient(ingredient) + assert burger.ingredients == [ingredient, ingredient] and len(burger.ingredients) == 2 + + def test_remove_ingredient_by_index(self, burger): + """Удаление ингредиента по индексу.""" + ing1 = Ingredient(*TEST_SAUCE) + ing2 = Ingredient(*TEST_FILLING_1) + burger.ingredients = [ing1, ing2] + burger.remove_ingredient(0) + assert burger.ingredients == [ing2] + + def test_move_ingredient_changes_order(self, burger): + """Перемещение меняет порядок ингредиентов.""" + ing1 = Ingredient(*TEST_SAUCE) + ing2 = Ingredient(*TEST_FILLING_1) + ing3 = Ingredient(*TEST_FILLING_2) + burger.ingredients = [ing1, ing2, ing3] + burger.move_ingredient(0, 2) + assert burger.ingredients == [ing2, ing3, ing1] + + def test_get_price(self, full_burger): + """Проверка расчёта цены.""" + price = full_burger.get_price() + assert price == 270.0 + + def test_get_receipt_format(self, full_burger): + """Проверка формата чека.""" + receipt = full_burger.get_receipt() + expected_price = (TEST_BUN["price"] * 2 + TEST_SAUCE["price"] + TEST_FILLING_1["price"]) + expected = RECEIPT_TEMPLATE.format( + bun=TEST_BUN["name"], + sauce=TEST_SAUCE["name"], + filling=TEST_FILLING_1["name"], + price=expected_price + ) + assert receipt == expected \ No newline at end of file diff --git a/tests/test_database.py b/tests/test_database.py new file mode 100644 index 000000000..f1c800ea4 --- /dev/null +++ b/tests/test_database.py @@ -0,0 +1,55 @@ +import pytest +from data import EXPECTED_BUNS, EXPECTED_INGREDIENTS + +class TestDatabase: + + def test_available_buns_returns_list(self, database): + """Метод available_buns возвращает список""" + result = database.available_buns() + assert isinstance(result, list) + + def test_available_buns_not_empty(self, database): + """Список булочек не пустой""" + result = database.available_buns() + assert len(result) > 0 + + def test_available_buns_count(self, database): + """Количество булочек""" + result = database.available_buns() + assert len(result) == 3 + + def test_available_ingredients_returns_list(self, database): + """Метод available_ingredients возвращает список""" + result = database.available_ingredients() + assert isinstance(result, list) + + def test_available_ingredients_not_empty(self, database): + """Список ингредиентов не пустой""" + result = database.available_ingredients() + assert len(result) > 0 + + def test_available_ingredients_count(self, database): + """Количество ингредиентов""" + result = database.available_ingredients() + assert len(result) == 6 + + @pytest.mark.parametrize("expected_bun", EXPECTED_BUNS) + def test_available_buns_contains_expected(self, database, expected_bun): + """Проверяет, что каждая ожидаемая булочка присутствует""" + buns = database.available_buns() + assert any( + bun.get_name() == expected_bun.get_name() and + bun.get_price() == expected_bun.get_price() + for bun in buns + ) + + @pytest.mark.parametrize("expected_ingredient", EXPECTED_INGREDIENTS) + def test_available_ingredients_contains_expected(self, database, expected_ingredient): + """Проверяет, что каждый ожидаемый ингредиент присутствует""" + ingredients = database.available_ingredients() + assert any( + ingredient.get_type() == expected_ingredient.get_type() and + ingredient.get_name() == expected_ingredient.get_name() and + ingredient.get_price() == expected_ingredient.get_price() + for ingredient in ingredients + ) \ No newline at end of file diff --git a/tests/test_ingredient.py b/tests/test_ingredient.py new file mode 100644 index 000000000..753aa29e1 --- /dev/null +++ b/tests/test_ingredient.py @@ -0,0 +1,27 @@ +import pytest +from praktikum.ingredient import Ingredient +from praktikum.ingredient_types import INGREDIENT_TYPE_SAUCE +from data import TEST_INGREDIENT_DATA + +class TestIngredient: + + @pytest.mark.parametrize("ingredient_type, expected_type", TEST_INGREDIENT_DATA["types"]) + def test_get_type_returns_correct_type(self, ingredient_type, expected_type): + """Метод get_type возвращает правильный тип.""" + ingredient = Ingredient(ingredient_type, "Название ингридиента", 100.0) + assert ingredient.get_type() == expected_type + + @pytest.mark.parametrize("name, expected_name", TEST_INGREDIENT_DATA["names"]) + def test_get_name_returns_correct_name(self, name, expected_name): + """Метод get_name возвращает правильное имя.""" + ingredient = Ingredient(INGREDIENT_TYPE_SAUCE, name, 100.0) + assert ingredient.get_name() == expected_name + + @pytest.mark.parametrize("price, expected_price", TEST_INGREDIENT_DATA["prices"]) + def test_get_price_returns_correct_price(self, price, expected_price): + """Метод get_price возвращает правильную цену.""" + ingredient = Ingredient(INGREDIENT_TYPE_SAUCE, "Название ингридиента", price) + assert ingredient.get_price() == expected_price + + +