From c4b8098241edcf3c9fd2d71a9a4647dee23ef315 Mon Sep 17 00:00:00 2001 From: Stas Basov Date: Mon, 6 Apr 2026 20:33:50 +0300 Subject: [PATCH 1/2] =?UTF-8?q?=D0=AE=D0=BD=D0=B8=D1=82-=D1=82=D0=B5=D1=81?= =?UTF-8?q?=D1=82=D1=8B=20=D0=B4=D0=BB=D1=8F=20=D0=BF=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=B5=D1=80=D0=BA=D0=B8=20=D0=BF=D1=80=D0=BE=D0=B3=D1=80=D0=B0?= =?UTF-8?q?=D0=BC=D0=BC=D1=8B,=20=D0=BA=D0=BE=D1=82=D0=BE=D1=80=D0=B0?= =?UTF-8?q?=D1=8F=20=D0=BF=D0=BE=D0=BC=D0=BE=D0=B3=D0=B0=D0=B5=D1=82=20?= =?UTF-8?q?=D0=B7=D0=B0=D0=BA=D0=B0=D0=B7=D0=B0=D1=82=D1=8C=20=D0=B1=D1=83?= =?UTF-8?q?=D1=80=D0=B3=D0=B5=D1=80=20=D0=B2=20Stellar=20Burgers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .coverage | Bin 0 -> 53248 bytes .gitignore | 23 ++++++++ README.md | 4 -- test_burger.py | 145 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 168 insertions(+), 4 deletions(-) create mode 100644 .coverage create mode 100644 .gitignore create mode 100644 test_burger.py diff --git a/.coverage b/.coverage new file mode 100644 index 0000000000000000000000000000000000000000..6618185f05d3b15a976d6f0b40c57606f2c74af8 GIT binary patch literal 53248 zcmeI)U2oe|7zc1W?vf@=<)TtWT{ZRGptf3?5q3ct7f{wpOiZvshd_$RoaCf6jqTKS z`f`C##-t%W0^%!h%SRX=f*US(g@h)qx(lAi$IeUJOjCQYZ2DVG>e%NTKj(Mek|xbp zTX*eHil*l~Rw!<2Gn%ez9}A&rT9$6pbW64j?Mx&O=(j$wKWaCtm4119+WcC}r@zt6 z@20PstNES$zf-^E*RuDg>`XCRq7&F4009U<;EfUJZsjwD`FZ`}5200S$ zx4+z6-`*74>z~}+6zZ5*&I#I9SH-&Uy+hHKzG&JlDQvf4*R9ZYcSN`=lhmC+Hh9gV zW3*~!Tiu*hi1MtFm@p|T!ug&wG!@wEnY z`kBwk87Gf3Hz_#ROIZ6E`O=g*irMWrH6s7MrnR&q;KuWQhZiT3$MB(QP(MF(}m5&QC+9k1*+xVZmv6@&J-3F^oQA~8^x^^|H=$? zp`<0xnMRXSj@Bk>uk&T1xISYH@boj6^!9PdnaGZUG@+??K3 zBZB88zFirr1Rv=Sfl~{?%ZJ~#!d-DTc0NpjFI`C&KAamBIEPRz^L_f!OezZbXCu;g zXwv7KF%&W%>4*H8JYGGpS~Q!qE!(FdOLMSV0R$&(Sd`eRd7Uuozx*)jp1k(-<5dOp zA1C&dY9&fe!~32W1U4qI~Riw81h4P1)dRAv)2?|k}7_Jlw08!__}$b(GNBV zKmY;|fB*y_009U<00Izz00iDV0Ygve8GikrGXK`hf9MVy1Rwwb2tWV=5P$##AOHaf zKmY=-r9eJqTr-o8g}ghX8w>OCX8_(Wm2Z~b%TcXT=2OjlYX0|HRuDl$00Izz00bZa z0SG_<0uX=z1R&58$Q#%6TVTyN%wFjAKfeEOyc-tLK>z{} zfB*y_009U<00Izz00b^6V9 zQot~#v+Di-XPWtJEJH+45P$##AOHafKmY;|fB*y_009VGOkhf%$Y!tp+WqT~-yL1O z|9_&HCl@OWxgY=m2tWV=5P$##AOHafKmY;|7;AwE`ZGZE{=YUe)^Q>@2tWV=5P$## zAOHafKmY;|fB*z8DZual `$ pip install -r requirements.txt` - **Запуск автотестов и создание HTML-отчета о покрытии** > `$ pytest --cov=praktikum --cov-report=html` diff --git a/test_burger.py b/test_burger.py new file mode 100644 index 000000000..8677121c1 --- /dev/null +++ b/test_burger.py @@ -0,0 +1,145 @@ +import os +import sys +sys.path.insert(0, os.path.dirname(__file__)) +from unittest.mock import Mock + +# Подмена модулей praktikum для корректного импорта Burger +from bun import Bun +from ingredient import Ingredient + +mock_praktikum = Mock() +mock_bun_module = Mock() +mock_bun_module.Bun = Bun +mock_ingredient_module = Mock() +mock_ingredient_module.Ingredient = Ingredient + +sys.modules['praktikum'] = mock_praktikum +sys.modules['praktikum.bun'] = mock_bun_module +sys.modules['praktikum.ingredient'] = mock_ingredient_module + +from burger import Burger +import pytest + +@pytest.fixture +def burger(): + return Burger() + +@pytest.fixture +def mock_bun(): + bun = Mock(spec=Bun) + bun.get_name.return_value = "black bun" + bun.get_price.return_value = 100 + return bun + +class TestBurger: + def test_set_buns(self, burger, mock_bun): + burger.set_buns(mock_bun) + assert burger.bun == mock_bun + + def test_add_ingredient(self, burger): + ingredient = Mock(spec=Ingredient) + burger.add_ingredient(ingredient) + assert len(burger.ingredients) == 1 + assert burger.ingredients[0] == ingredient + + def test_remove_ingredient_first(self, burger): + ing1 = Mock(spec=Ingredient) + ing2 = Mock(spec=Ingredient) + burger.add_ingredient(ing1) + burger.add_ingredient(ing2) + burger.remove_ingredient(0) + assert len(burger.ingredients) == 1 + assert burger.ingredients[0] == ing2 + + def test_remove_ingredient_last(self, burger): + ing1 = Mock(spec=Ingredient) + ing2 = Mock(spec=Ingredient) + burger.add_ingredient(ing1) + burger.add_ingredient(ing2) + burger.remove_ingredient(1) + assert len(burger.ingredients) == 1 + assert burger.ingredients[0] == ing1 + + def test_remove_ingredient_single(self, burger): + ing = Mock(spec=Ingredient) + burger.add_ingredient(ing) + burger.remove_ingredient(0) + assert len(burger.ingredients) == 0 + + def test_remove_ingredient_invalid_index(self, burger): + ing = Mock(spec=Ingredient) + burger.add_ingredient(ing) + with pytest.raises(IndexError): + burger.remove_ingredient(1) + + def test_move_ingredient_same_index(self, burger): + ing1 = Mock(spec=Ingredient) + ing2 = Mock(spec=Ingredient) + burger.add_ingredient(ing1) + burger.add_ingredient(ing2) + burger.move_ingredient(0, 0) + assert burger.ingredients[0] == ing1 + assert burger.ingredients[1] == ing2 + + def test_move_ingredient(self, burger): + ing1 = Mock(spec=Ingredient) + ing2 = Mock(spec=Ingredient) + burger.add_ingredient(ing1) + burger.add_ingredient(ing2) + burger.move_ingredient(0, 1) + assert burger.ingredients[0] == ing2 + assert burger.ingredients[1] == ing1 + + def test_move_ingredient_from_end_to_start(self, burger): + ing1 = Mock(spec=Ingredient) + ing2 = Mock(spec=Ingredient) + burger.add_ingredient(ing1) + burger.add_ingredient(ing2) + burger.move_ingredient(1, 0) + assert burger.ingredients[0] == ing2 + assert burger.ingredients[1] == ing1 + + def test_get_price_only_bun(self, burger, mock_bun): + burger.set_buns(mock_bun) + assert burger.get_price() == 200 + + def test_get_price_no_bun(self, burger): + ing = Mock(spec=Ingredient) + burger.add_ingredient(ing) + with pytest.raises(AttributeError): + burger.get_price() + + def test_get_receipt_no_bun(self, burger): + ing = Mock(spec=Ingredient) + burger.add_ingredient(ing) + with pytest.raises(AttributeError): + burger.get_receipt() + + @pytest.mark.parametrize("sauce_count, filling_count, expected_price", [ + (0, 0, 200), + (1, 0, 250), + (1, 1, 320) + ]) + def test_get_receipt(self, burger, mock_bun, sauce_count, filling_count, expected_price): + burger.set_buns(mock_bun) + for _ in range(sauce_count): + sauce = Mock(spec=Ingredient) + sauce.get_type.return_value = "sauce" + sauce.get_name.return_value = "hot sauce" + sauce.get_price.return_value = 50 + burger.add_ingredient(sauce) + for _ in range(filling_count): + filling = Mock(spec=Ingredient) + filling.get_type.return_value = "filling" + filling.get_name.return_value = "cheese" + filling.get_price.return_value = 70 + burger.add_ingredient(filling) + lines = [f"(==== {mock_bun.get_name()} ====)"] + for ing in burger.ingredients: + lines.append(f"= {ing.get_type()} {ing.get_name()} =") + lines.append(f"(==== {mock_bun.get_name()} ====)") + lines.append("") + lines.append(f"Price: {expected_price}") + expected = "\n".join(lines) + assert burger.get_receipt() == expected + \ No newline at end of file From 2130ce9ade28f450ad23f94fa3d6133f573256ca Mon Sep 17 00:00:00 2001 From: Stas Basov Date: Wed, 8 Apr 2026 10:48:00 +0300 Subject: [PATCH 2/2] =?UTF-8?q?=D0=9C=D0=BE=D0=BA=D0=B8=20=D0=B8=20=D1=84?= =?UTF-8?q?=D0=B8=D0=BA=D1=81=D1=82=D1=83=D1=80=D1=8B=20=D0=B2=D1=8B=D0=BD?= =?UTF-8?q?=D0=B5=D1=81=D0=B5=D0=BD=D1=8B=20=D0=B2=20=D0=BE=D1=82=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=B5=20=D1=84=D0=B0=D0=B9=D0=BB?= =?UTF-8?q?=D1=8B.=20=D0=A2=D0=B5=D1=81=D1=82=D1=8B=20=D1=83=D0=BB=D1=83?= =?UTF-8?q?=D1=87=D1=88=D0=B5=D0=BD=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 - README.md | 7 +- tests/__init__.py | 0 tests/conftest.py | 29 +++++++ tests/mocks.py | 14 ++++ test_burger.py => tests/test_burger.py | 111 +++++++++++-------------- 6 files changed, 92 insertions(+), 70 deletions(-) create mode 100644 tests/__init__.py create mode 100644 tests/conftest.py create mode 100644 tests/mocks.py rename test_burger.py => tests/test_burger.py (57%) diff --git a/.gitignore b/.gitignore index 7c8ef193c..1eb5137c4 100644 --- a/.gitignore +++ b/.gitignore @@ -13,7 +13,6 @@ __pycache__/ .ruff_cache/ allure-results/ allure-report/ -htmlcov/ .logs/ *.log .idea/ diff --git a/README.md b/README.md index 07b95e184..99da38412 100644 --- a/README.md +++ b/README.md @@ -8,13 +8,8 @@ Процент покрытия 100% (отчет: `htmlcov/index.html`) -### Структура проекта - -- `praktikum` - пакет, содержащий код программы -- `tests` - пакет, содержащий тесты, разделенные по классам. Например, `bun_test.py`, `burger_test.py` и т.д. - ### Запуск автотестов **Запуск автотестов и создание HTML-отчета о покрытии** -> `$ pytest --cov=praktikum --cov-report=html` +> `pytest --cov=Diplom_1.burger --cov-report=html --cov-report=term` 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..a27390039 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,29 @@ +import sys +from unittest.mock import MagicMock, Mock + +sys.modules['praktikum'] = MagicMock() +sys.modules['praktikum.bun'] = MagicMock() +sys.modules['praktikum.ingredient'] = MagicMock() +sys.modules['praktikum.bun'].Bun = Mock() +sys.modules['praktikum.ingredient'].Ingredient = Mock() + +from Diplom_1.burger import Burger +from .mocks import create_mock_bun, create_mock_ingredient + +import pytest + +@pytest.fixture +def burger(): + return Burger() + +@pytest.fixture +def mock_bun(): + return create_mock_bun() + +@pytest.fixture +def mock_sauce(): + return create_mock_ingredient(ingredient_type="sauce", name="hot sauce", price=50) + +@pytest.fixture +def mock_filling(): + return create_mock_ingredient(ingredient_type="filling", name="cheese", price=70) diff --git a/tests/mocks.py b/tests/mocks.py new file mode 100644 index 000000000..829f2b6c9 --- /dev/null +++ b/tests/mocks.py @@ -0,0 +1,14 @@ +from unittest.mock import Mock + +def create_mock_bun(name="black bun", price=100): + bun = Mock() + bun.get_name.return_value = name + bun.get_price.return_value = price + return bun + +def create_mock_ingredient(ingredient_type="sauce", name="hot sauce", price=50): + ing = Mock() + ing.get_type.return_value = ingredient_type + ing.get_name.return_value = name + ing.get_price.return_value = price + return ing diff --git a/test_burger.py b/tests/test_burger.py similarity index 57% rename from test_burger.py rename to tests/test_burger.py index 8677121c1..985b39d36 100644 --- a/test_burger.py +++ b/tests/test_burger.py @@ -1,35 +1,5 @@ -import os -import sys -sys.path.insert(0, os.path.dirname(__file__)) -from unittest.mock import Mock - -# Подмена модулей praktikum для корректного импорта Burger -from bun import Bun -from ingredient import Ingredient - -mock_praktikum = Mock() -mock_bun_module = Mock() -mock_bun_module.Bun = Bun -mock_ingredient_module = Mock() -mock_ingredient_module.Ingredient = Ingredient - -sys.modules['praktikum'] = mock_praktikum -sys.modules['praktikum.bun'] = mock_bun_module -sys.modules['praktikum.ingredient'] = mock_ingredient_module - -from burger import Burger import pytest - -@pytest.fixture -def burger(): - return Burger() - -@pytest.fixture -def mock_bun(): - bun = Mock(spec=Bun) - bun.get_name.return_value = "black bun" - bun.get_price.return_value = 100 - return bun +from unittest.mock import Mock class TestBurger: def test_set_buns(self, burger, mock_bun): @@ -37,14 +7,14 @@ def test_set_buns(self, burger, mock_bun): assert burger.bun == mock_bun def test_add_ingredient(self, burger): - ingredient = Mock(spec=Ingredient) + ingredient = Mock() burger.add_ingredient(ingredient) assert len(burger.ingredients) == 1 assert burger.ingredients[0] == ingredient def test_remove_ingredient_first(self, burger): - ing1 = Mock(spec=Ingredient) - ing2 = Mock(spec=Ingredient) + ing1 = Mock() + ing2 = Mock() burger.add_ingredient(ing1) burger.add_ingredient(ing2) burger.remove_ingredient(0) @@ -52,8 +22,8 @@ def test_remove_ingredient_first(self, burger): assert burger.ingredients[0] == ing2 def test_remove_ingredient_last(self, burger): - ing1 = Mock(spec=Ingredient) - ing2 = Mock(spec=Ingredient) + ing1 = Mock() + ing2 = Mock() burger.add_ingredient(ing1) burger.add_ingredient(ing2) burger.remove_ingredient(1) @@ -61,20 +31,20 @@ def test_remove_ingredient_last(self, burger): assert burger.ingredients[0] == ing1 def test_remove_ingredient_single(self, burger): - ing = Mock(spec=Ingredient) + ing = Mock() burger.add_ingredient(ing) burger.remove_ingredient(0) assert len(burger.ingredients) == 0 def test_remove_ingredient_invalid_index(self, burger): - ing = Mock(spec=Ingredient) + ing = Mock() burger.add_ingredient(ing) with pytest.raises(IndexError): burger.remove_ingredient(1) def test_move_ingredient_same_index(self, burger): - ing1 = Mock(spec=Ingredient) - ing2 = Mock(spec=Ingredient) + ing1 = Mock() + ing2 = Mock() burger.add_ingredient(ing1) burger.add_ingredient(ing2) burger.move_ingredient(0, 0) @@ -82,8 +52,8 @@ def test_move_ingredient_same_index(self, burger): assert burger.ingredients[1] == ing2 def test_move_ingredient(self, burger): - ing1 = Mock(spec=Ingredient) - ing2 = Mock(spec=Ingredient) + ing1 = Mock() + ing2 = Mock() burger.add_ingredient(ing1) burger.add_ingredient(ing2) burger.move_ingredient(0, 1) @@ -91,8 +61,8 @@ def test_move_ingredient(self, burger): assert burger.ingredients[1] == ing1 def test_move_ingredient_from_end_to_start(self, burger): - ing1 = Mock(spec=Ingredient) - ing2 = Mock(spec=Ingredient) + ing1 = Mock() + ing2 = Mock() burger.add_ingredient(ing1) burger.add_ingredient(ing2) burger.move_ingredient(1, 0) @@ -101,45 +71,60 @@ def test_move_ingredient_from_end_to_start(self, burger): def test_get_price_only_bun(self, burger, mock_bun): burger.set_buns(mock_bun) - assert burger.get_price() == 200 + expected_price = mock_bun.get_price() * 2 + assert burger.get_price() == expected_price def test_get_price_no_bun(self, burger): - ing = Mock(spec=Ingredient) + ing = Mock() burger.add_ingredient(ing) with pytest.raises(AttributeError): burger.get_price() def test_get_receipt_no_bun(self, burger): - ing = Mock(spec=Ingredient) + ing = Mock() burger.add_ingredient(ing) with pytest.raises(AttributeError): burger.get_receipt() - @pytest.mark.parametrize("sauce_count, filling_count, expected_price", [ - (0, 0, 200), - (1, 0, 250), - (1, 1, 320) + @pytest.mark.parametrize("sauce_count, filling_count", [ + (0, 0), + (1, 0), + (1, 1) ]) - def test_get_receipt(self, burger, mock_bun, sauce_count, filling_count, expected_price): + def test_get_receipt(self, burger, mock_bun, mock_sauce, mock_filling, sauce_count, filling_count): burger.set_buns(mock_bun) + ingredients = [] + for _ in range(sauce_count): - sauce = Mock(spec=Ingredient) - sauce.get_type.return_value = "sauce" - sauce.get_name.return_value = "hot sauce" - sauce.get_price.return_value = 50 - burger.add_ingredient(sauce) + burger.add_ingredient(mock_sauce) + ingredients.append(mock_sauce) for _ in range(filling_count): - filling = Mock(spec=Ingredient) - filling.get_type.return_value = "filling" - filling.get_name.return_value = "cheese" - filling.get_price.return_value = 70 - burger.add_ingredient(filling) + burger.add_ingredient(mock_filling) + ingredients.append(mock_filling) + + bun_price = mock_bun.get_price() + total_price = bun_price * 2 + sum(ing.get_price() for ing in ingredients) + lines = [f"(==== {mock_bun.get_name()} ====)"] for ing in burger.ingredients: lines.append(f"= {ing.get_type()} {ing.get_name()} =") lines.append(f"(==== {mock_bun.get_name()} ====)") lines.append("") - lines.append(f"Price: {expected_price}") + lines.append(f"Price: {total_price}") expected = "\n".join(lines) + assert burger.get_receipt() == expected + + def test_get_price_without_bun_and_ingredients(self, burger): + with pytest.raises(AttributeError): + burger.get_price() + + def test_move_ingredient_invalid_index(self, burger): + ing = Mock() + burger.add_ingredient(ing) + with pytest.raises(IndexError): + burger.move_ingredient(1, 0) + with pytest.raises(IndexError): + burger.move_ingredient(-2, 0) + burger.move_ingredient(0, 5) \ No newline at end of file