From 6dedf8d9d873016a1934a9159d88a8ad9c0099e0 Mon Sep 17 00:00:00 2001 From: Lev Spivak Date: Sat, 6 Dec 2025 14:40:54 +0300 Subject: [PATCH] Diplom_1. Tests for Burger ClassV1 --- .gitignore | 68 +++++++++++++++ README.md | 4 +- __init__.py => 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 praktikum.py => praktikum/praktikum.py | 0 tests/__init__.py | 0 tests/conftest.py | 27 ++++++ tests/data.py | 83 +++++++++++++++++++ tests/test_burger.py | 80 ++++++++++++++++++ 13 files changed, 260 insertions(+), 2 deletions(-) create mode 100644 .gitignore rename __init__.py => praktikum/__init__.py (100%) 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%) rename praktikum.py => praktikum/praktikum.py (100%) create mode 100644 tests/__init__.py create mode 100644 tests/conftest.py create mode 100644 tests/data.py create mode 100644 tests/test_burger.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..8b9738f3b --- /dev/null +++ b/.gitignore @@ -0,0 +1,68 @@ +# -------------------------------------------------------------------------------- +# File created using 'AnGitIgnored' extensions for Visual Studio Code: +# https://marketplace.visualstudio.com/items?itemName=AnAppWiLos.angitignored +#------------------------------------------------------------------------------- +# Created by https://www.toptal.com/developers/gitignore/api/windows,visualstudiocode +# Edit at https://www.toptal.com/developers/gitignore?templates=windows,visualstudiocode + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# End of https://www.toptal.com/developers/gitignore/api/windows,visualstudiocode + +# Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option) + +/tests/__pycache__ + +# Coverage +htmlcov/ +.coverage +.coverage.* +*.cover +coverage.xml + +# Отредактируйте .gitignore чтобы было: +echo "__pycache__/" >> .gitignore +echo "*.pyc" >> .gitignore \ No newline at end of file diff --git a/README.md b/README.md index 272081708..967758437 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` - пакет, содержащий тест`test_burger.py`, conftest.py и data.py ### Запуск автотестов 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/praktikum.py b/praktikum/praktikum.py similarity index 100% rename from praktikum.py rename to praktikum/praktikum.py 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..0cdf24aad --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,27 @@ +# conftest.py + +import pytest +from unittest.mock import Mock + + +@pytest.fixture +def mock_bun(): + mock = Mock() + mock.get_name.return_value = "black bun" + mock.get_price.return_value = 100.0 + return mock + + +@pytest.fixture +def mock_ingredient(): + mock = Mock() + mock.get_type.return_value = "SAUCE" + mock.get_name.return_value = "hot sauce" + mock.get_price.return_value = 100.0 + return mock + + +@pytest.fixture +def empty_burger(): + from praktikum.burger import Burger + return Burger() \ No newline at end of file diff --git a/tests/data.py b/tests/data.py new file mode 100644 index 000000000..80ad50daf --- /dev/null +++ b/tests/data.py @@ -0,0 +1,83 @@ +#data.py + +from unittest.mock import Mock + + +def get_price_test_cases(): + return [ + (100.0, [100.0, 200.0], 500.0), # 100*2 + 100 + 200 = 500 (а не 400!) + (200.0, [100.0, 200.0, 300.0], 1000.0), # 200*2 + 100 + 200 + 300 = 1000 (а не 800!) + (300.0, [], 600.0), # 300*2 = 600 ✓ + (150.0, [50.0], 350.0), # 150*2 + 50 = 350 ✓ + ] + + +def get_receipt_test_cases(): + return [ + ( + "black bun", + 100.0, + [], + ["(==== black bun ====)", "(==== black bun ====)", "", "Price: 200.0"] # Пустая строка есть! + ), + ( + "white bun", + 200.0, + [("SAUCE", "hot sauce", 100.0)], + ["(==== white bun ====)", "= sauce hot sauce =", "(==== white bun ====)", "", "Price: 500.0"] # Пустая строка есть! + ), + ( + "red bun", + 300.0, + [ + ("SAUCE", "sour cream", 200.0), + ("FILLING", "cutlet", 100.0) + ], + ["(==== red bun ====)", "= sauce sour cream =", "= filling cutlet =", "(==== red bun ====)", "", "Price: 900.0"] # Пустая строка есть! + ), + ] + + +def create_burger_for_price_test(bun_price, ingredient_prices): + """Создает бургер для теста цены""" + from praktikum.burger import Burger + + burger = Burger() + + # Создаем булку + mock_bun = Mock() + mock_bun.get_price.return_value = bun_price + + # Настраиваем бургер + burger.set_buns(mock_bun) + + # Добавляем ингредиенты + for price in ingredient_prices: + mock_ingredient = Mock() + mock_ingredient.get_price.return_value = price + burger.add_ingredient(mock_ingredient) + + return burger + + +def create_burger_for_receipt_test(bun_name, bun_price, ingredients_data): + """Создает бургер для теста рецепта""" + from praktikum.burger import Burger + + burger = Burger() + + # Создаем булку + mock_bun = Mock() + mock_bun.get_name.return_value = bun_name + mock_bun.get_price.return_value = bun_price + burger.set_buns(mock_bun) + + # Добавляем ингредиенты + for ingredient_type, name, price in ingredients_data: + mock_ingredient = Mock() + mock_ingredient.get_type.return_value = ingredient_type + mock_ingredient.get_name.return_value = name + mock_ingredient.get_price.return_value = price + burger.add_ingredient(mock_ingredient) + + return burger \ No newline at end of file diff --git a/tests/test_burger.py b/tests/test_burger.py new file mode 100644 index 000000000..ba73e3dc7 --- /dev/null +++ b/tests/test_burger.py @@ -0,0 +1,80 @@ +#test_burger.py + +import pytest +from unittest.mock import Mock +from .data import ( + get_price_test_cases, + get_receipt_test_cases, + create_burger_for_price_test, + create_burger_for_receipt_test +) + + +class TestBurger: + + def test_burger_initialization(self, empty_burger): + assert empty_burger.bun is None + assert empty_burger.ingredients == [] + + def test_set_buns(self, empty_burger, mock_bun): + empty_burger.set_buns(mock_bun) + assert empty_burger.bun == mock_bun + + def test_add_ingredient(self, empty_burger, mock_ingredient): + empty_burger.add_ingredient(mock_ingredient) + assert len(empty_burger.ingredients) == 1 + assert empty_burger.ingredients[0] == mock_ingredient + + + def test_remove_ingredient(self, empty_burger): + mock_ingredient = Mock() + empty_burger.add_ingredient(mock_ingredient) + empty_burger.remove_ingredient(0) + assert len(empty_burger.ingredients) == 0 + + def test_remove_ingredient_invalid_index(self, empty_burger): + mock_ingredient = Mock() + empty_burger.add_ingredient(mock_ingredient) + with pytest.raises(IndexError): + empty_burger.remove_ingredient(10) + + def test_move_ingredient(self, empty_burger): + mock_ingredient1 = Mock() + mock_ingredient2 = Mock() + + empty_burger.add_ingredient(mock_ingredient1) + empty_burger.add_ingredient(mock_ingredient2) + + empty_burger.move_ingredient(0, 1) + assert empty_burger.ingredients[0] == mock_ingredient2 + assert empty_burger.ingredients[1] == mock_ingredient1 + + def test_move_ingredient_invalid_index(self, empty_burger): + mock_ingredient = Mock() + empty_burger.add_ingredient(mock_ingredient) + with pytest.raises(IndexError): + empty_burger.move_ingredient(10, 0) + + @pytest.mark.parametrize("bun_price,ingredient_prices,expected", get_price_test_cases()) + def test_get_price(self, bun_price, ingredient_prices, expected): + burger = create_burger_for_price_test(bun_price, ingredient_prices) + assert burger.get_price() == expected + + def test_get_price_no_bun(self, empty_burger): + mock_ingredient = Mock() + empty_burger.add_ingredient(mock_ingredient) + with pytest.raises(AttributeError): + empty_burger.get_price() + + @pytest.mark.parametrize("bun_name,bun_price,ingredients_data,expected_lines", get_receipt_test_cases()) + def test_get_receipt(self, bun_name, bun_price, ingredients_data, expected_lines): + burger = create_burger_for_receipt_test(bun_name, bun_price, ingredients_data) + receipt = burger.get_receipt() + lines = receipt.split('\n') + + assert len(lines) == len(expected_lines) + assert lines == expected_lines + + def test_get_receipt_no_bun(self, empty_burger): + with pytest.raises(AttributeError): + empty_burger.get_receipt() \ No newline at end of file