From 4af44a3229ca4413aaf7defb62860d612da0f103 Mon Sep 17 00:00:00 2001 From: Konstantin Date: Sat, 21 Mar 2026 15:30:38 +0300 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20=D1=80=D0=B5=D1=84=D0=B0=D0=BA?= =?UTF-8?q?=D1=82=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=20=D1=81=D1=82=D1=80=D1=83?= =?UTF-8?q?=D0=BA=D1=82=D1=83=D1=80=D1=8B=20(=D0=BF=D0=B5=D1=80=D0=B5?= =?UTF-8?q?=D0=BD=D0=BE=D1=81=20=D0=B2=20=D0=BF=D0=B0=D0=BA=D0=B5=D1=82=20?= =?UTF-8?q?praktikum)=20=D0=B8=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=8E=D0=BD=D0=B8=D1=82-=D1=82?= =?UTF-8?q?=D0=B5=D1=81=D1=82=D0=BE=D0=B2=20=D0=B4=D0=BB=D1=8F=20Burger=20?= =?UTF-8?q?=D1=81=20=D0=BF=D0=BE=D0=BA=D1=80=D1=8B=D1=82=D0=B8=D0=B5=D0=BC?= =?UTF-8?q?=20100%?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 + conftest.py | 60 ++++++++++ praktikum/__init__.py | 0 bun.py => praktikum/bun.py | 0 burger.py => praktikum/burger.py | 0 database.py => praktikum/database.py | 0 ingredient.py => praktikum/ingredient.py | 0 .../ingredient_types.py | 0 test_burger.py | 109 ++++++++++++++++++ 9 files changed, 173 insertions(+) create mode 100644 .gitignore create mode 100644 conftest.py create mode 100644 praktikum/__init__.py rename bun.py => praktikum/bun.py (100%) rename burger.py => praktikum/burger.py (100%) rename database.py => praktikum/database.py (100%) rename ingredient.py => praktikum/ingredient.py (100%) rename ingredient_types.py => praktikum/ingredient_types.py (100%) create mode 100644 test_burger.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..2930e0560 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +venv/ +__pycache__/ +.pytest_cache/ +*.pyc \ No newline at end of file diff --git a/conftest.py b/conftest.py new file mode 100644 index 000000000..accfba5f8 --- /dev/null +++ b/conftest.py @@ -0,0 +1,60 @@ +from praktikum.burger import Burger +from praktikum.bun import Bun +from praktikum.ingredient import Ingredient + +from unittest.mock import Mock +import pytest + + +@pytest.fixture +def burger_instance(): + burger = Burger() + return burger + + +@pytest.fixture +def mock_bun(): + bun_mock = Mock() + bun_mock.get_name.return_value = 'Test Bun Name' + bun_mock.get_price.return_value = 1000 + return bun_mock + + +@pytest.fixture +def mock_ingredient(): + ingredient_mock = Mock() + ingredient_mock.get_type.return_value = "FILLING" + ingredient_mock.get_name.return_value = "Test Ingredient Name" + ingredient_mock.get_price.return_value = 50 + return ingredient_mock + + +@pytest.fixture +def mock_two_ingredient(): + ingredient_two_mock = Mock() + ingredient_two_mock.get_type.return_value = "SAUCE" + ingredient_two_mock.get_name.return_value = "Test Ingredient Name" + ingredient_two_mock.get_price.return_value = 70 + return ingredient_two_mock + + +@pytest.fixture +def mock_ingredient_a(): + ingredient_a_mock = Mock() + ingredient_a_mock.get_name.return_value = "A" + return ingredient_a_mock + + +@pytest.fixture +def mock_ingredient_b(): + ingredient_b_mock = Mock() + ingredient_b_mock.get_name.return_value = "B" + return ingredient_b_mock + + +@pytest.fixture +def mock_ingredient_c(): + ingredient_c_mock = Mock() + ingredient_c_mock.get_name.return_value = "C" + return ingredient_c_mock + 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 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/test_burger.py b/test_burger.py new file mode 100644 index 000000000..3ff0eec75 --- /dev/null +++ b/test_burger.py @@ -0,0 +1,109 @@ +from praktikum.burger import Burger +from praktikum.bun import Bun +from praktikum.ingredient import Ingredient + +from unittest.mock import Mock +import pytest + + + +class TestBurgerInitialization: + + # Тест 1: Добавление булки + def test_set_bun_sets_correctly(self, burger_instance, mock_bun): + burger_instance.set_buns(mock_bun) + assert burger_instance.bun == mock_bun + assert burger_instance.bun.get_name() == 'Test Bun Name' + + # Тест 2: Добавление ингридиентов в конец списка + def test_add_ingredient_appends_to_list(self, burger_instance, mock_ingredient): + assert len(burger_instance.ingredients) == 0 + burger_instance.add_ingredient(mock_ingredient) + assert len(burger_instance.ingredients) == 1 + assert burger_instance.ingredients[0] == mock_ingredient + + +class TestBurgerManipulation: + + + # Тест 1: Удаление (Позитивный) + def test_remove_ingredient_removes_correctly(self, burger_instance, mock_ingredient, mock_two_ingredient): + burger_instance.add_ingredient(mock_ingredient) + burger_instance.add_ingredient(mock_two_ingredient) + assert len(burger_instance.ingredients) == 2 + burger_instance.remove_ingredient(0) + assert len(burger_instance.ingredients) == 1 + assert burger_instance.ingredients[0] == mock_two_ingredient + + + # Тест 2: Удаление (Негативный / Ошибка) + def test_remove_ingredient_raises_error_on_invalid_index(self, burger_instance, mock_ingredient): + burger_instance.add_ingredient(mock_ingredient) + with pytest.raises(IndexError): + burger_instance.remove_ingredient(99) + + # Тест 3: Перемещение (Позитивный) --- + def test_move_ingredient_changes_order(self, burger_instance, mock_ingredient_a, mock_ingredient_b, mock_ingredient_c): + burger_instance.add_ingredient(mock_ingredient_a) + burger_instance.add_ingredient(mock_ingredient_b) + burger_instance.add_ingredient(mock_ingredient_c) + burger_instance.move_ingredient(0, 2) + assert burger_instance.ingredients[0] == mock_ingredient_b + assert burger_instance.ingredients[1] == mock_ingredient_c + assert burger_instance.ingredients[2] == mock_ingredient_a + + + # Тест 4: Перемещение (Негативный / Ошибка) + def test_move_ingredient_raises_error_on_invalid_index(self, burger_instance, mock_ingredient): + burger_instance.add_ingredient(mock_ingredient) + with pytest.raises(IndexError): + burger_instance.move_ingredient(5, 0) + + +class TestBurgerPrice: + + @pytest.mark.parametrize("bun_price, ingredient_prices, expected_total", [ + (100, [], 200), + (150, [50], 350), + (200, [10, 20], 430),]) + + def test_get_price_calculation(self, burger_instance, bun_price, ingredient_prices, expected_total): + mock_bun = Mock() + mock_bun.get_price.return_value = bun_price + mock_bun.get_name.return_value = "Test Bun" + burger_instance.set_buns(mock_bun) + for price in ingredient_prices: + mock_ingredient = Mock() + mock_ingredient.get_price.return_value = price + mock_ingredient.get_type.return_value = "FILLING" + mock_ingredient.get_name.return_value = "Test Ingredient" + burger_instance.add_ingredient(mock_ingredient) + actual_price = burger_instance.get_price() + assert actual_price == expected_total + + +class TestBurgerReceipt: + + + @pytest.mark.parametrize("bun_name, ing_type, ing_name, expected_ing_type_lower",[ + ('White Bun', "FILLING", "Meat Ball", "filling" ), + ("Black Bun", "SAUCE", "Hot Sauce", "sauce"), + ("Red Bun", "SaUcE", "Ketchup","sauce"), + ]) + def test_get_receipt_format(self, burger_instance, bun_name, ing_name, ing_type, expected_ing_type_lower): + mock_bun = Mock() + mock_bun.get_name.return_value = bun_name + mock_bun.get_price.return_value = 1500 + + mock_ingredient = Mock() + mock_ingredient.get_type.return_value = ing_type + mock_ingredient.get_name.return_value = ing_name + mock_ingredient.get_price.return_value = 420 + + expected_price = (1500*2) + 420 + + burger_instance.set_buns(mock_bun) + burger_instance.add_ingredient(mock_ingredient) + expected_receipt = f"(==== {bun_name} ====)\n= {expected_ing_type_lower} {ing_name} =\n(==== {bun_name} ====)\n\nPrice: {expected_price}" + actual_receipt = burger_instance.get_receipt() + assert actual_receipt == expected_receipt From fafe86b7d2884a8cfbf501cf1a0e20cc90d4a2a8 Mon Sep 17 00:00:00 2001 From: Konstantin Date: Sat, 21 Mar 2026 16:06:49 +0300 Subject: [PATCH 2/4] =?UTF-8?q?feat:=20=D0=AE=D0=BD=D0=B8=D1=82=20=D1=82?= =?UTF-8?q?=D0=B5=D1=81=D1=82=D1=8B=20=D0=B4=D0=BB=D1=8F=20Stellar=20Burge?= =?UTF-8?q?rs=20=D1=81=D0=BE=20100%=20=D0=BF=D0=BE=D0=BA=D1=80=D1=8B=D1=82?= =?UTF-8?q?=D0=B8=D0=B5=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + requirements.txt | 2 ++ tests/__init__.py | 0 tests/bun_test.py | 28 ++++++++++++++++++ test_burger.py => tests/burger_test.py | 0 conftest.py => tests/conftest.py | 0 tests/database_test.py | 39 ++++++++++++++++++++++++++ tests/ingredient_test.py | 32 +++++++++++++++++++++ 8 files changed, 102 insertions(+) create mode 100644 requirements.txt create mode 100644 tests/__init__.py create mode 100644 tests/bun_test.py rename test_burger.py => tests/burger_test.py (100%) rename conftest.py => tests/conftest.py (100%) create mode 100644 tests/database_test.py create mode 100644 tests/ingredient_test.py diff --git a/.gitignore b/.gitignore index 2930e0560..10c95f77c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ venv/ __pycache__/ .pytest_cache/ +.coverage *.pyc \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 000000000..cffeec658 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +pytest +pytest-cov \ No newline at end of file diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/bun_test.py b/tests/bun_test.py new file mode 100644 index 000000000..2cd6c31e5 --- /dev/null +++ b/tests/bun_test.py @@ -0,0 +1,28 @@ +import pytest +from praktikum.bun import Bun + +class TestBun: + + + @pytest.mark.parametrize("name, price", [ + ("Black Bun", 100), + ("White Bun", 50.5), + ("", 0), + ("Super Big Bun", 999.99) + ]) + def test_bun_creation_and_getters(self, name, price): + bun = Bun(name, price) + # Проверяем, что конструктор сохранил данные (через атрибуты) + assert bun.name == name + assert bun.price == price + # Проверяем работу геттеров + assert bun.get_name() == name + assert bun.get_price() == price + + + def test_bun_attributes_modification(self): + bun = Bun("Old Name", 100) + bun.name = "New Name" + bun.price = 200 + assert bun.get_name() == "New Name" + assert bun.get_price() == 200 \ No newline at end of file diff --git a/test_burger.py b/tests/burger_test.py similarity index 100% rename from test_burger.py rename to tests/burger_test.py diff --git a/conftest.py b/tests/conftest.py similarity index 100% rename from conftest.py rename to tests/conftest.py diff --git a/tests/database_test.py b/tests/database_test.py new file mode 100644 index 000000000..6081012bf --- /dev/null +++ b/tests/database_test.py @@ -0,0 +1,39 @@ +import pytest +from praktikum.database import Database +from praktikum.bun import Bun +from praktikum.ingredient import Ingredient + +class TestDatabase: + + @pytest.fixture + def database_instance(self): + return Database() + + def test_database_initialization(self, database_instance): + assert len(database_instance.buns) > 0 + assert len(database_instance.ingredients) > 0 + + def test_available_buns_returns_list(self, database_instance): + buns = database_instance.available_buns() + + assert isinstance(buns, list) + assert len(buns) == 3 + + for bun in buns: + assert isinstance(bun, Bun) + + assert buns[0].get_name() == "black bun" + assert buns[0].get_price() == 100 + + def test_available_ingredients_returns_list(self, database_instance): + ingredients = database_instance.available_ingredients() + assert isinstance(ingredients, list) + assert len(ingredients) == 6 + + for ingredient in ingredients: + assert isinstance(ingredient, Ingredient) + + first_ing = ingredients[0] + from praktikum.ingredient_types import INGREDIENT_TYPE_SAUCE + assert first_ing.get_type() == INGREDIENT_TYPE_SAUCE + assert first_ing.get_name() == "hot sauce" \ No newline at end of file diff --git a/tests/ingredient_test.py b/tests/ingredient_test.py new file mode 100644 index 000000000..f956aaddc --- /dev/null +++ b/tests/ingredient_test.py @@ -0,0 +1,32 @@ +import pytest +from praktikum.ingredient import Ingredient +from praktikum.ingredient_types import INGREDIENT_TYPE_SAUCE, INGREDIENT_TYPE_FILLING + +class TestIngredient: + + @pytest.mark.parametrize("ing_type, name, price", [ + (INGREDIENT_TYPE_SAUCE, "Hot Sauce", 100), + (INGREDIENT_TYPE_FILLING, "Cutlet", 250.5), + ("CUSTOM_TYPE", "Custom Item", 0), + (INGREDIENT_TYPE_SAUCE, "Mayo", 99.99) + ]) + def test_ingredient_creation_and_getters(self, ing_type, name, price): + ingredient = Ingredient(ing_type, name, price) + + assert ingredient.type == ing_type + assert ingredient.name == name + assert ingredient.price == price + + assert ingredient.get_type() == ing_type + assert ingredient.get_name() == name + assert ingredient.get_price() == price + + def test_ingredient_modification(self): + ingredient = Ingredient(INGREDIENT_TYPE_SAUCE, "Old Sauce", 100) + ingredient.type = INGREDIENT_TYPE_FILLING + ingredient.name = "New Filling" + ingredient.price = 500 + + assert ingredient.get_type() == INGREDIENT_TYPE_FILLING + assert ingredient.get_name() == "New Filling" + assert ingredient.get_price() == 500 \ No newline at end of file From 551c772c42abfca1abb395806126be7c596cd50a Mon Sep 17 00:00:00 2001 From: Konstantin Date: Mon, 30 Mar 2026 13:07:48 +0300 Subject: [PATCH 3/4] =?UTF-8?q?fix:=20=D0=A2=D0=B0=D0=BA=20=D0=BA=D0=B0?= =?UTF-8?q?=D0=BA=20=D0=B1=D1=8B=D0=BB=D0=BE=20=D1=83=D0=BA=D0=B0=D0=B7?= =?UTF-8?q?=D0=B0=D0=BD=D0=BE=20=D0=BD=D0=B0=20=D1=82=D0=BE=20=D1=87=D1=82?= =?UTF-8?q?=D0=BE=20=D0=B4=D0=BE=D1=81=D1=82=D0=B0=D1=82=D0=BE=D1=87=D0=BD?= =?UTF-8?q?=D0=BE=20=D0=BE=D0=B4=D0=BD=D0=BE=D0=B3=D0=BE=20=D0=BA=D0=BB?= =?UTF-8?q?=D0=B0=D1=81=D1=81=D0=B0,=20=D0=B1=D1=8B=D0=BB=D0=B8=20=D1=83?= =?UTF-8?q?=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D1=8B=20=D0=B8=D0=B7=D0=B1=D1=8B?= =?UTF-8?q?=D1=82=D0=BE=D1=87=D0=BD=D1=8B=D0=B5=20=D1=82=D0=B5=D1=81=D1=82?= =?UTF-8?q?=D1=8B=20=D0=B4=D0=BB=D1=8F=20Bun,=20Ingredient=20=D0=B8=20Data?= =?UTF-8?q?base.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 +++ tests/bun_test.py | 28 ---------------------------- tests/database_test.py | 39 --------------------------------------- tests/ingredient_test.py | 32 -------------------------------- 4 files changed, 3 insertions(+), 99 deletions(-) delete mode 100644 tests/bun_test.py delete mode 100644 tests/database_test.py delete mode 100644 tests/ingredient_test.py diff --git a/README.md b/README.md index 272081708..73e34e56c 100644 --- a/README.md +++ b/README.md @@ -22,3 +22,6 @@ **Запуск автотестов и создание HTML-отчета о покрытии** > `$ pytest --cov=praktikum --cov-report=html` + + +python -m pytest tests/burger_test.py -v \ No newline at end of file diff --git a/tests/bun_test.py b/tests/bun_test.py deleted file mode 100644 index 2cd6c31e5..000000000 --- a/tests/bun_test.py +++ /dev/null @@ -1,28 +0,0 @@ -import pytest -from praktikum.bun import Bun - -class TestBun: - - - @pytest.mark.parametrize("name, price", [ - ("Black Bun", 100), - ("White Bun", 50.5), - ("", 0), - ("Super Big Bun", 999.99) - ]) - def test_bun_creation_and_getters(self, name, price): - bun = Bun(name, price) - # Проверяем, что конструктор сохранил данные (через атрибуты) - assert bun.name == name - assert bun.price == price - # Проверяем работу геттеров - assert bun.get_name() == name - assert bun.get_price() == price - - - def test_bun_attributes_modification(self): - bun = Bun("Old Name", 100) - bun.name = "New Name" - bun.price = 200 - assert bun.get_name() == "New Name" - assert bun.get_price() == 200 \ No newline at end of file diff --git a/tests/database_test.py b/tests/database_test.py deleted file mode 100644 index 6081012bf..000000000 --- a/tests/database_test.py +++ /dev/null @@ -1,39 +0,0 @@ -import pytest -from praktikum.database import Database -from praktikum.bun import Bun -from praktikum.ingredient import Ingredient - -class TestDatabase: - - @pytest.fixture - def database_instance(self): - return Database() - - def test_database_initialization(self, database_instance): - assert len(database_instance.buns) > 0 - assert len(database_instance.ingredients) > 0 - - def test_available_buns_returns_list(self, database_instance): - buns = database_instance.available_buns() - - assert isinstance(buns, list) - assert len(buns) == 3 - - for bun in buns: - assert isinstance(bun, Bun) - - assert buns[0].get_name() == "black bun" - assert buns[0].get_price() == 100 - - def test_available_ingredients_returns_list(self, database_instance): - ingredients = database_instance.available_ingredients() - assert isinstance(ingredients, list) - assert len(ingredients) == 6 - - for ingredient in ingredients: - assert isinstance(ingredient, Ingredient) - - first_ing = ingredients[0] - from praktikum.ingredient_types import INGREDIENT_TYPE_SAUCE - assert first_ing.get_type() == INGREDIENT_TYPE_SAUCE - assert first_ing.get_name() == "hot sauce" \ No newline at end of file diff --git a/tests/ingredient_test.py b/tests/ingredient_test.py deleted file mode 100644 index f956aaddc..000000000 --- a/tests/ingredient_test.py +++ /dev/null @@ -1,32 +0,0 @@ -import pytest -from praktikum.ingredient import Ingredient -from praktikum.ingredient_types import INGREDIENT_TYPE_SAUCE, INGREDIENT_TYPE_FILLING - -class TestIngredient: - - @pytest.mark.parametrize("ing_type, name, price", [ - (INGREDIENT_TYPE_SAUCE, "Hot Sauce", 100), - (INGREDIENT_TYPE_FILLING, "Cutlet", 250.5), - ("CUSTOM_TYPE", "Custom Item", 0), - (INGREDIENT_TYPE_SAUCE, "Mayo", 99.99) - ]) - def test_ingredient_creation_and_getters(self, ing_type, name, price): - ingredient = Ingredient(ing_type, name, price) - - assert ingredient.type == ing_type - assert ingredient.name == name - assert ingredient.price == price - - assert ingredient.get_type() == ing_type - assert ingredient.get_name() == name - assert ingredient.get_price() == price - - def test_ingredient_modification(self): - ingredient = Ingredient(INGREDIENT_TYPE_SAUCE, "Old Sauce", 100) - ingredient.type = INGREDIENT_TYPE_FILLING - ingredient.name = "New Filling" - ingredient.price = 500 - - assert ingredient.get_type() == INGREDIENT_TYPE_FILLING - assert ingredient.get_name() == "New Filling" - assert ingredient.get_price() == 500 \ No newline at end of file From 3db8a2a249c29e1c0c313b1b3b7f684443930946 Mon Sep 17 00:00:00 2001 From: Konstantin Date: Mon, 30 Mar 2026 14:12:47 +0300 Subject: [PATCH 4/4] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20Burger=20=D0=BF=D0=BE?= =?UTF-8?q?=20=D0=B7=D0=B0=D0=BC=D0=B5=D1=87=D0=B0=D0=BD=D0=B8=D1=8F=D0=BC?= =?UTF-8?q?=20=D1=80=D0=B5=D0=B2=D1=8C=D1=8E=D0=B5=D1=80=D0=B0.=20=D0=A3?= =?UTF-8?q?=D0=B1=D1=80=D0=B0=D0=BD=D1=8B=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5?= =?UTF-8?q?=D1=80=D0=BA=D0=B8=20=D0=B0=D1=82=D1=80=D0=B8=D0=B1=D1=83=D1=82?= =?UTF-8?q?=D0=BE=D0=B2,=20=D0=BE=D0=B1=D0=B5=D1=81=D0=BF=D0=B5=D1=87?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=B0=D1=82=D0=BE=D0=BC=D0=B0=D1=80=D0=BD?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D1=8C,=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D0=BB=D0=B8=D1=88=D0=BD=D0=B8=D0=B5=20=D1=84?= =?UTF-8?q?=D0=B0=D0=B9=D0=BB=D1=8B.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 17 ++++++--- image.png | Bin 0 -> 21071 bytes tests/burger_test.py | 82 +++++++++++++++++++++++++++++++------------ tests/conftest.py | 24 ++++++++----- 4 files changed, 87 insertions(+), 36 deletions(-) create mode 100644 image.png diff --git a/README.md b/README.md index 73e34e56c..efcc4a532 100644 --- a/README.md +++ b/README.md @@ -4,14 +4,14 @@ ### Реализованные сценарии -Созданы юнит-тесты, покрывающие классы `Bun`, `Burger`, `Ingredient`, `Database` +Созданы юнит-тесты, покрывающие класс `Burger` Процент покрытия 100% (отчет: `htmlcov/index.html`) ### Структура проекта - `praktikum` - пакет, содержащий код программы -- `tests` - пакет, содержащий тесты, разделенные по классам. Например, `bun_test.py`, `burger_test.py` и т.д. +- `tests` - пакет, содержащий тесты, разделенные по классам - `burger_test.py` ### Запуск автотестов @@ -21,7 +21,16 @@ **Запуск автотестов и создание HTML-отчета о покрытии** -> `$ pytest --cov=praktikum --cov-report=html` +> `python -m pytest --cov=praktikum.burger --cov-report=html` -python -m pytest tests/burger_test.py -v \ No newline at end of file +`python -m pytest tests/burger_test.py -v` + + +![Покрытие 100%](image.png) + +Исправления по замечаниям ревьюера: +Принцип «Черного ящика»: Полностью исключена проверка внутренних атрибутов (self.bun, self.ingredients, len()). Все ассерты переписаны на проверку поведения через публичные методы get_price() и get_receipt(). +Атомарность тестов: Тесты разбиты на изолированные сценарии. Каждый тест проверяет одно конкретное поведение метода (влияние на цену, порядок в чеке, возникновение ошибки) без лишних промежуточных проверок состояния. +Покрытие: Достигнуто 100% покрытие кода класса Burger (отчет htmlcov сформирован, красных строк нет). +Структура: Удалены избыточные тесты для классов Bun, Ingredient и Database, оставлены только тесты для целевого класса Burger согласно требованиям задания. \ No newline at end of file diff --git a/image.png b/image.png new file mode 100644 index 0000000000000000000000000000000000000000..742ece68ce45a66ecc3716f95cafaf1edfb8a9c3 GIT binary patch literal 21071 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%0A50t{pu; z<8dS=sd?=NDhuT|gGyV35)}d3mH&X%RKWFE&k3Y8PUFi~MdQ-K@EMdyBFd{?yZwk1 zLvBW_eVxj6v{(e$sQi(k6*Y94#H>ZFryIVPI8q`*xGTJn0gQ6k;r-C**{)4Hmnx9c#VdIr^ov8-kEtfAY)#Mhr; zecrk%nm9m^4gjAoyzrG*A1dDx+T`#-={4eOO0GZ`t!E1TF0!atNc3g@i-H;}ZuG8* zDS&4!ZWD(06V8^@SwbC>(HKBCXo#thR@fhgA*l?E#n% z#m-)WLa<~c5&mkH_Wgve=Ke>Dl!VE(C9^>m>mA2g<-!Wz*)JJGOTNppZOZC=yy^f) zCt!%%&XMgHJs@!1YuE5VYTd+~7x(F11<}#M$D9Xb&`J(4R5>;wp!x-t2}x?_?)zjh zBIR%sFxMgvF|+Lbu8Od8X^-mCSV;{BIRwy8S04hOj&dtfg7d5*xf8<1Ht+qbPYc9i z<2qe6N*)s}fGL5GIQ4OYKY*$2kTGp{3n`%;QwVTHec2ON4Oh z?k&1!->)ueKl*`k60*+bks5d?F*LpXU1=9)aBTYx+-|)H8~aYB4ko)`yP5SF8{5;b zUDZ`LyNDR2Nkh#&duL~UzNpyXQ2+-zO7qMJ3$C=o-6WnFr#F;`(}K1xPlqBpA!8qG zAbt+F^&{_Mql1aRaWytCTXO_it)XdNotyLUEWC8DHsaz1y;$Q!ZiaTO_4tDnD2%9_qb8#F|}#O#v|zJv1Mb@ zRgcpMP1zmm`9&^5X9NHK+tQGZM=!&FDB<+peeuoSCm|M58$9$EJz4ig2RSuL3(<9}gBCezihV}yaA1bx+rVU+NTihqVoj2|V+?)ex zW|#K?FY?u?%I5(UA|Q+pD&w>w{;OIOw;hh=)6A-gT$sTR1Kqn5v`PI%g73e5S8tQ? ziLJej&!p>jA;iZ*&UzR*sNkIT&}H+#oeCun!&f|;`*2h+XiP&t6v4l*eaLa<3q8k$ zI^h4=E($ijoq_hvvOw-WZhomMMF+N%p*{kUIMf=_rM5KL^M(N$D2c}>A6Fz7FS;hbiY^YcJkDIk_52GAG7_OjWnIrL4G~n?}OhOU-O2|B`O4w z3TxRn6+)wY64K;U>$E4tY& zB4TuVYtnPG>*wl?$qR{|KBJpb^~(1M<=%YC0^+dO{gHv4p-w9j8MLjHH#37~6 z@m`&OhBka7ZAE*DUBk9>@=(d7s?^z~*O7t44?i0=ZP!@E5Z4jz{58)f2O|94tJ&l* z*_^Ovj?|h6GCNrQ-mwF& z=om0_ZO|g-j1)}Js+yQ_960VgWRH=Y@UfAk(1LDjczKjAOtox&dPSb_JxS4b0<|!c zjLmJmQ)|~ru%fc&a$oAlvUt7HU}pY{fTfE>fs5HvqVVq^Tg%MGNvXuf++{lM{G|gE zH?POtRi}q}A#%&i^>lU9%lIWr*9-a2kR{&bA8WmFK|svMpsO1l=Uc_F*^`ZP>mY$& zu7Mv{iEW>>r{osS<39haz0=h$N3FWWK$$vlAg~%s^>f1YIWNv-;;K?krXQJ+B^vBY zcB+Y6y7HB@@jt8EpYt8RNGOL>FBCJIyTzvSahyNZ9tW(&nyqVub5MCm+!6f-38Hfra_>* zyK-FBB>Ky6`0*97DhbOQn97-vr9=EMCg$GFOgP7-$L@Yx}Koxkz0fQr4%YsX-^a~((a6yagnUT zz^>ekX_R#D#+sk09CAm<`yP=A-;DOJI_L|n;+=pduc9pO2w!}e z{sx3ERdKDEx6pRf)i>X@arI5T&*cHrv;eF7KdTq`=f(X$S+!8Ij-GfN+tjvby3s)^ MbGy@|lb-Sa0qL)Cc>n+a literal 0 HcmV?d00001 diff --git a/tests/burger_test.py b/tests/burger_test.py index 3ff0eec75..8521cab3b 100644 --- a/tests/burger_test.py +++ b/tests/burger_test.py @@ -9,31 +9,59 @@ class TestBurgerInitialization: - # Тест 1: Добавление булки - def test_set_bun_sets_correctly(self, burger_instance, mock_bun): + # ИСПРАВЛЕННЫЙ ТЕСТ 1: Проверяем set_buns через влияние на цену + def test_set_bun_calculates_price_correctly(self, burger_instance, mock_bun): + # Arrange: mock_bun имеет цену 1000 (из фикстуры) burger_instance.set_buns(mock_bun) - assert burger_instance.bun == mock_bun - assert burger_instance.bun.get_name() == 'Test Bun Name' + # Если булка установилась верно, цена должна быть 1000 * 2 = 2000. + # Если бы булка не установилась, метод get_price() упал бы с ошибкой (AttributeError). + assert burger_instance.get_price() == 2000 - # Тест 2: Добавление ингридиентов в конец списка - def test_add_ingredient_appends_to_list(self, burger_instance, mock_ingredient): - assert len(burger_instance.ingredients) == 0 + + # Тест 2 НОВЫЙ: Проверяем поведение метода add_ingredient через изменение цены + def test_add_ingredient_increases_price(self, burger_instance, mock_bun, mock_ingredient): + # Устанавливаем булку, чтобы цена считалась корректно (иначе будет ошибка или 0) + burger_instance.set_buns(mock_bun) + # Цена булки 1000 (из фикстуры), значит база = 2000. + # Цена ингредиента 50 (из фикстуры). Ожидаемый итог: 2050. + expected_price = 2050 + # Добавляем ингредиент burger_instance.add_ingredient(mock_ingredient) - assert len(burger_instance.ingredients) == 1 - assert burger_instance.ingredients[0] == mock_ingredient + # Проверяем результат через публичный метод get_price() + assert burger_instance.get_price() == expected_price + + + # Тест 3 НОВЫЙ: Проверяем поведение метода add_ingredient формирование чека + def test_add_ingredient_appears_in_receipt(self, burger_instance, mock_bun, mock_ingredient): + # Устанавливаем булку + burger_instance.set_buns(mock_bun) + # Добавляем ингредиент + burger_instance.add_ingredient(mock_ingredient) + # Получаем чек + receipt = burger_instance.get_receipt() + # Проверяем, что имя ингредиента есть в чеке + # Мы знаем из фикстуры, что имя "Test Ingredient Name" + assert "Test Ingredient Name" in receipt + class TestBurgerManipulation: - - # Тест 1: Удаление (Позитивный) - def test_remove_ingredient_removes_correctly(self, burger_instance, mock_ingredient, mock_two_ingredient): - burger_instance.add_ingredient(mock_ingredient) - burger_instance.add_ingredient(mock_two_ingredient) - assert len(burger_instance.ingredients) == 2 + # Тест 1 : Позитивный сценарий удаления ингредиента (проверка через изменение цены) + def test_remove_ingredient_decreases_price(self, burger_instance, mock_bun, mock_ingredient, mock_two_ingredient): + # Подготовка данных + # Из фикстур знаем: + # mock_ingredient price = 50 + # mock_two_ingredient price = 70 + burger_instance.set_buns(mock_bun) # Цена булки 1000 -> база 2000 + burger_instance.add_ingredient(mock_ingredient) # +50 -> 2050 + burger_instance.add_ingredient(mock_two_ingredient) # +70 -> 2120 + # Удаляем первый ингредиент (тот, что стоит 50) burger_instance.remove_ingredient(0) - assert len(burger_instance.ingredients) == 1 - assert burger_instance.ingredients[0] == mock_two_ingredient + # Проверяем поведение через цену + # Ожидаемая цена: 2125 - 50 = 2070 + expected_price_after_remove = 2070 + assert burger_instance.get_price() == expected_price_after_remove # Тест 2: Удаление (Негативный / Ошибка) @@ -42,15 +70,23 @@ def test_remove_ingredient_raises_error_on_invalid_index(self, burger_instance, with pytest.raises(IndexError): burger_instance.remove_ingredient(99) - # Тест 3: Перемещение (Позитивный) --- - def test_move_ingredient_changes_order(self, burger_instance, mock_ingredient_a, mock_ingredient_b, mock_ingredient_c): - burger_instance.add_ingredient(mock_ingredient_a) + # ИСПРАВЛЕННЫЙ ТЕСТ 3: Проверяем move_ingredient через порядок в чеке + def test_move_ingredient_changes_order_in_receipt(self, burger_instance, mock_ingredient_a, mock_ingredient_b, mock_ingredient_c, mock_bun): + # Берём данные из фикстуры (3 мока) + burger_instance.set_buns(mock_bun) + burger_instance.add_ingredient(mock_ingredient_a) # Порядок: A, B, C burger_instance.add_ingredient(mock_ingredient_b) burger_instance.add_ingredient(mock_ingredient_c) + # Перемещаем A (индекс 0) в конец (индекс 2). Ожидаемый порядок: B, C, A burger_instance.move_ingredient(0, 2) - assert burger_instance.ingredients[0] == mock_ingredient_b - assert burger_instance.ingredients[1] == mock_ingredient_c - assert burger_instance.ingredients[2] == mock_ingredient_a + # Получаем чек и проверяем порядок следования имен в строке + receipt = burger_instance.get_receipt() + # Находим индексы вхождений имен в строку чека + pos_a = receipt.find("Ingredient_A") + pos_b = receipt.find("Ingredient_B") + pos_c = receipt.find("Ingredient_C") + # Проверяем, что все найдены и порядок верный: B идет раньше C, C раньше A + assert pos_b < pos_c < pos_a # Тест 4: Перемещение (Негативный / Ошибка) diff --git a/tests/conftest.py b/tests/conftest.py index accfba5f8..2178dbd55 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -40,21 +40,27 @@ def mock_two_ingredient(): @pytest.fixture def mock_ingredient_a(): - ingredient_a_mock = Mock() - ingredient_a_mock.get_name.return_value = "A" - return ingredient_a_mock + ing_a = Mock() + ing_a.get_name.return_value = "Ingredient_A" + ing_a.get_type.return_value = "FILLING" + ing_a.get_price.return_value = 10 + return ing_a @pytest.fixture def mock_ingredient_b(): - ingredient_b_mock = Mock() - ingredient_b_mock.get_name.return_value = "B" - return ingredient_b_mock + ing_b = Mock() + ing_b.get_name.return_value = "Ingredient_B" + ing_b.get_type.return_value = "FILLING" + ing_b.get_price.return_value = 10 + return ing_b @pytest.fixture def mock_ingredient_c(): - ingredient_c_mock = Mock() - ingredient_c_mock.get_name.return_value = "C" - return ingredient_c_mock + ing_c = Mock() + ing_c.get_name.return_value = "Ingredient_C" + ing_c.get_type.return_value = "FILLING" + ing_c.get_price.return_value = 10 + return ing_c