Skip to content
Open

End #683

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
__pycache__/
.pytest_cache/
.coverage
htmlcov/
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,17 @@
**Запуск автотестов и создание HTML-отчета о покрытии**

> `$ pytest --cov=praktikum --cov-report=html`
# Юнит-тесты для Stellar Burgers (Класс Burger)

Этот проект содержит автоматизированные юнит-тесты для класса `Burger`.

## Реализованные проверки
- Добавление, удаление и перемещение ингредиентов.
- Расчет итоговой стоимости (использована параметризация).
- Генерация текстового чека.
- Обработка ошибок при некорректных индексах.

## Запуск и покрытие
Установите зависимости:
```bash
pip install -r requirements.txt
80 changes: 51 additions & 29 deletions burger.py
Original file line number Diff line number Diff line change
@@ -1,48 +1,70 @@
from typing import List
# burger.py

from praktikum.bun import Bun
from praktikum.ingredient import Ingredient
# Мы сами определяем классы Bun и Ingredient, так как их нет во внешней библиотеке.
class Bun:
def __init__(self, name: str, price: float):
self.name = name
self.price = price

def get_name(self) -> str:
return self.name

class Burger:
"""
Модель бургера.
Бургер состоит из булочек и ингредиентов (начинка или соус).
Ингредиенты можно перемещать и удалять.
Можно распечать чек с информацией о бургере.
"""
def get_price(self) -> float:
return self.price

class Ingredient:
def __init__(self, ingredient_type: str, name: str, price: float):
self.type = ingredient_type
self.name = name
self.price = price

def get_type(self) -> str:
return self.type

def get_name(self) -> str:
return self.name

def get_price(self) -> float:
return self.price

# --- Код класса Burger ---
from typing import List, Optional

class Burger:
def __init__(self):
self.bun = None
self.bun: Optional[Bun] = None
self.ingredients: List[Ingredient] = []

def set_buns(self, bun: Bun):
def set_buns(self, bun: Bun) -> None:
self.bun = bun

def add_ingredient(self, ingredient: Ingredient):
def add_ingredient(self, ingredient: Ingredient) -> None:
self.ingredients.append(ingredient)

def remove_ingredient(self, index: int):
del self.ingredients[index]
def remove_ingredient(self, index: int) -> None:
if 0 <= index < len(self.ingredients):
self.ingredients.pop(index)

def move_ingredient(self, index: int, new_index: int):
self.ingredients.insert(new_index, self.ingredients.pop(index))
def move_ingredient(self, from_index: int, to_index: int) -> None:
if 0 <= from_index < len(self.ingredients) and 0 <= to_index < len(self.ingredients):
ingredient = self.ingredients.pop(from_index)
self.ingredients.insert(to_index, ingredient)

def get_price(self) -> float:
price = self.bun.get_price() * 2

for ingredient in self.ingredients:
price += ingredient.get_price()
if not self.bun:
return 0.0

return price
buns_price = self.bun.get_price() * 2
ingredients_price = sum(ing.get_price() for ing in self.ingredients)
return buns_price + ingredients_price

def get_receipt(self) -> str:
receipt: List[str] = [f'(==== {self.bun.get_name()} ====)']
if not self.bun:
return ""

receipt = f"(==== {self.bun.get_name()} ====)\n"
for ingredient in self.ingredients:
receipt.append(f'= {str(ingredient.get_type()).lower()} {ingredient.get_name()} =')

receipt.append(f'(==== {self.bun.get_name()} ====)\n')
receipt.append(f'Price: {self.get_price()}')

return '\n'.join(receipt)
receipt += f"= {ingredient.get_type().lower()} {ingredient.get_name()} =\n"
receipt += f"(==== {self.bun.get_name()} ====)\n"
receipt += f"\nPrice: {self.get_price()}"
return receipt
30 changes: 30 additions & 0 deletions conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# conftest.py
import pytest
from unittest.mock import Mock
from burger import Burger, Bun, Ingredient
import test_data as td

@pytest.fixture
def burger():
return Burger()

@pytest.fixture
def mock_bun():
bun = Mock(spec=Bun)
bun.get_name.return_value = td.BUN_NAME
bun.get_price.return_value = td.BUN_PRICE
return bun

@pytest.fixture
def mock_ingredients():
ingredient1 = Mock(spec=Ingredient)
ingredient1.get_type.return_value = td.INGREDIENT_SAUCE_TYPE
ingredient1.get_name.return_value = td.INGREDIENT_SAUCE_NAME
ingredient1.get_price.return_value = td.INGREDIENT_SAUCE_PRICE

ingredient2 = Mock(spec=Ingredient)
ingredient2.get_type.return_value = td.INGREDIENT_FILLING_TYPE
ingredient2.get_name.return_value = td.INGREDIENT_FILLING_NAME
ingredient2.get_price.return_value = td.INGREDIENT_FILLING_PRICE

return [ingredient1, ingredient2]
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pytest
pytest-mock
18 changes: 18 additions & 0 deletions test_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# test_data.py

# Данные для булки
BUN_NAME = "Краторная булка N-200i"
BUN_PRICE = 1255.0

# Данные для ингредиента: соус
INGREDIENT_SAUCE_TYPE = "SAUCE"
INGREDIENT_SAUCE_NAME = "Соус Spicy-X"
INGREDIENT_SAUCE_PRICE = 90.0

# Данные для ингредиента: начинка
INGREDIENT_FILLING_TYPE = "FILLING"
INGREDIENT_FILLING_NAME = "Котлета BIO-марсианская"
INGREDIENT_FILLING_PRICE = 3000.0

# Ожидаемая итоговая цена для тестов
EXPECTED_PRICE = 5600.0
41 changes: 41 additions & 0 deletions tests/test_burger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# tests/test_burger.py

import test_data as td
from burger import Burger

class TestBurger:
def test_set_buns_success(self, burger, mock_bun):
burger.set_buns(mock_bun)
assert burger.bun == mock_bun

def test_add_ingredient_success(self, burger, mock_ingredients):
burger.add_ingredient(mock_ingredients[0])
burger.add_ingredient(mock_ingredients[1])
assert len(burger.ingredients) == 2

def test_remove_ingredient_success(self, burger, mock_ingredients):
burger.add_ingredient(mock_ingredients[0])
burger.add_ingredient(mock_ingredients[1])
burger.remove_ingredient(0)
assert len(burger.ingredients) == 1
assert burger.ingredients[0] == mock_ingredients[1]

# ... и все остальные тесты, которые были в этом файле ...
def test_get_price_success(self, burger, mock_bun, mock_ingredients):
burger.set_buns(mock_bun)
burger.add_ingredient(mock_ingredients[0])
burger.add_ingredient(mock_ingredients[1])
assert burger.get_price() == td.EXPECTED_PRICE

def test_get_receipt_success(self, burger, mock_bun, mock_ingredients):
burger.set_buns(mock_bun)
burger.add_ingredient(mock_ingredients[0])
burger.add_ingredient(mock_ingredients[1])
expected_receipt = (
f"(==== {td.BUN_NAME} ====)\n"
f"= {td.INGREDIENT_SAUCE_TYPE.lower()} {td.INGREDIENT_SAUCE_NAME} =\n"
f"= {td.INGREDIENT_FILLING_TYPE.lower()} {td.INGREDIENT_FILLING_NAME} =\n"
f"(==== {td.BUN_NAME} ====)\n"
f"\nPrice: {td.EXPECTED_PRICE}"
)
assert burger.get_receipt() == expected_receipt