Skip to content
Open
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
44 changes: 44 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg

# pytest
.pytest_cache/
.coverage
# htmlcov/ - отчет должен быть в репозитории
.tox/

# Virtual environments
venv/
env/
ENV/

# IDE
.vscode/
.idea/
*.swp
*.swo
*~

# OS
.DS_Store
Thumbs.db

25 changes: 1 addition & 24 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1 @@
## Задание 1: Юнит-тесты

### Автотесты для проверки программы, которая помогает заказать бургер в Stellar Burgers

### Реализованные сценарии

Созданы юнит-тесты, покрывающие классы `Bun`, `Burger`, `Ingredient`, `Database`

Процент покрытия 100% (отчет: `htmlcov/index.html`)

### Структура проекта

- `praktikum` - пакет, содержащий код программы
- `tests` - пакет, содержащий тесты, разделенные по классам. Например, `bun_test.py`, `burger_test.py` и т.д.

### Запуск автотестов

**Установка зависимостей**

> `$ pip install -r requirements.txt`

**Запуск автотестов и создание HTML-отчета о покрытии**

> `$ pytest --cov=praktikum --cov-report=html`
# Task_1
7 changes: 0 additions & 7 deletions ingredient_types.py

This file was deleted.

1 change: 1 addition & 0 deletions praktikum.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from praktikum.ingredient import Ingredient


def main():
def main():
# Инициализируем базу данных
database: Database = Database()
Expand Down
File renamed without changes.
6 changes: 2 additions & 4 deletions bun.py → praktikum/bun.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# Модель булочки для бургера.
# Булочке можно дать название и назначить цену.
class Bun:
"""
Модель булочки для бургера.
Булочке можно дать название и назначить цену.
"""

def __init__(self, name: str, price: float):
self.name = name
Expand Down
10 changes: 4 additions & 6 deletions burger.py → praktikum/burger.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@
from praktikum.ingredient import Ingredient


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

def __init__(self):
self.bun = None
Expand Down
4 changes: 1 addition & 3 deletions database.py → praktikum/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@
from praktikum.ingredient_types import INGREDIENT_TYPE_SAUCE, INGREDIENT_TYPE_FILLING


# Класс с методами по работе с базой данных.
class Database:
"""
Класс с методами по работе с базой данных.
"""

def __init__(self):
self.buns: List[Bun] = []
Expand Down
8 changes: 3 additions & 5 deletions ingredient.py → praktikum/ingredient.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
# Модель ингредиента.
# Ингредиент: начинка или соус.
# У ингредиента есть тип (начинка или соус), название и цена.
class Ingredient:
"""
Модель ингредиента.
Ингредиент: начинка или соус.
У ингредиента есть тип (начинка или соус), название и цена.
"""

def __init__(self, ingredient_type: str, name: str, price: float):
self.type = ingredient_type
Expand Down
5 changes: 5 additions & 0 deletions praktikum/ingredient_types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Перечисление с типами ингредиентов.
# SAUCE – соус
# FILLING – начинка
INGREDIENT_TYPE_SAUCE = 'SAUCE'
INGREDIENT_TYPE_FILLING = 'FILLING'
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pytest==7.4.3
pytest-cov==4.1.0

Empty file added tests/__init__.py
Empty file.
22 changes: 22 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Фикстуры для тестов.

import pytest
from praktikum.bun import Bun
from praktikum.ingredient import Ingredient
from tests.test_constants import (
BUN_BLACK, PRICE_100,
INGREDIENT_TYPE_SAUCE, INGREDIENT_HOT_SAUCE
)


@pytest.fixture
def ingredient():
# Фикстура для создания ингредиента.
return Ingredient(INGREDIENT_TYPE_SAUCE, INGREDIENT_HOT_SAUCE, PRICE_100)


@pytest.fixture
def bun():
# Фикстура для создания булочки.
return Bun(BUN_BLACK, PRICE_100)

27 changes: 27 additions & 0 deletions tests/test_bun.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import pytest
from praktikum.bun import Bun
from tests.test_constants import (
TEST_BUNS, BUN_TEST, PRICE_150
)


# Тесты для класса Bun.
class TestBun:

@pytest.mark.parametrize("name,price", TEST_BUNS)
def test_bun_get_name(self, name, price):
# Проверка получения названия булочки.
bun = Bun(name, price)
assert bun.get_name() == name

@pytest.mark.parametrize("name,price", TEST_BUNS)
def test_bun_get_price(self, name, price):
# Проверка получения цены булочки.
bun = Bun(name, price)
assert bun.get_price() == price

def test_bun_initialization(self):
# Проверка инициализации булочки.
bun = Bun(BUN_TEST, PRICE_150)
assert bun.name == BUN_TEST
assert bun.price == PRICE_150
155 changes: 155 additions & 0 deletions tests/test_burger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import pytest
from unittest.mock import Mock

from praktikum.burger import Burger
from praktikum.bun import Bun
from praktikum.ingredient import Ingredient
from tests.test_constants import (
BUN_BLACK, BUN_WHITE, BUN_RED, BUN_TEST,
PRICE_50, PRICE_100, PRICE_150, PRICE_200, PRICE_500, PRICE_400, PRICE_75,
INGREDIENT_TYPE_SAUCE, INGREDIENT_TYPE_FILLING,
INGREDIENT_HOT_SAUCE, INGREDIENT_SOUR_CREAM, INGREDIENT_CUTLET
)


class TestBurger:
# Тесты для класса Burger.

def test_set_buns(self, bun):
# Проверка установки булочек.
burger = Burger()
burger.set_buns(bun)
assert burger.bun == bun

def test_add_ingredient(self, ingredient):
# Проверка добавления ингредиента.
burger = Burger()
burger.add_ingredient(ingredient)
assert len(burger.ingredients) == 1
assert burger.ingredients[0] == ingredient

def test_add_multiple_ingredients(self):
# Проверка добавления нескольких ингредиентов.
burger = Burger()
ingredient1 = Ingredient(INGREDIENT_TYPE_SAUCE, INGREDIENT_HOT_SAUCE, PRICE_100)
ingredient2 = Ingredient(INGREDIENT_TYPE_FILLING, INGREDIENT_CUTLET, PRICE_100)
burger.add_ingredient(ingredient1)
burger.add_ingredient(ingredient2)
assert len(burger.ingredients) == 2

def test_remove_ingredient(self):
# Проверка удаления ингредиента.
burger = Burger()
ingredient1 = Ingredient(INGREDIENT_TYPE_SAUCE, INGREDIENT_HOT_SAUCE, PRICE_100)
ingredient2 = Ingredient(INGREDIENT_TYPE_FILLING, INGREDIENT_CUTLET, PRICE_100)
burger.add_ingredient(ingredient1)
burger.add_ingredient(ingredient2)
burger.remove_ingredient(0)
assert len(burger.ingredients) == 1
assert burger.ingredients[0] == ingredient2

def test_move_ingredient(self):
# Проверка перемещения ингредиента.
burger = Burger()
ingredient1 = Ingredient(INGREDIENT_TYPE_SAUCE, INGREDIENT_HOT_SAUCE, PRICE_100)
ingredient2 = Ingredient(INGREDIENT_TYPE_FILLING, INGREDIENT_CUTLET, PRICE_100)
ingredient3 = Ingredient(INGREDIENT_TYPE_SAUCE, INGREDIENT_SOUR_CREAM, PRICE_200)
burger.add_ingredient(ingredient1)
burger.add_ingredient(ingredient2)
burger.add_ingredient(ingredient3)
burger.move_ingredient(0, 2)
assert burger.ingredients[2] == ingredient1

@pytest.mark.parametrize("bun_name,bun_price,ingredient_count,expected_price", [
(BUN_BLACK, PRICE_100, 0, PRICE_200),
(BUN_WHITE, PRICE_50, 1, PRICE_200),
(BUN_RED, PRICE_100, 3, PRICE_500),
])
def test_get_price(self, bun_name, bun_price, ingredient_count, expected_price):
# Проверка расчета цены бургера.
burger = Burger()
bun = Bun(bun_name, bun_price)
burger.set_buns(bun)

# Добавляем ингредиенты с фиксированной ценой
for i in range(ingredient_count):
ingredient = Ingredient(INGREDIENT_TYPE_SAUCE, INGREDIENT_HOT_SAUCE, PRICE_100)
burger.add_ingredient(ingredient)

assert burger.get_price() == expected_price

def test_get_receipt(self, bun):
# Проверка получения чека.
burger = Burger()
burger.set_buns(bun)
ingredient1 = Ingredient(INGREDIENT_TYPE_SAUCE, INGREDIENT_HOT_SAUCE, PRICE_100)
ingredient2 = Ingredient(INGREDIENT_TYPE_FILLING, INGREDIENT_CUTLET, PRICE_100)
burger.add_ingredient(ingredient1)
burger.add_ingredient(ingredient2)

receipt = burger.get_receipt()
assert BUN_BLACK in receipt
assert INGREDIENT_HOT_SAUCE in receipt
assert INGREDIENT_CUTLET in receipt
assert f"Price: {PRICE_400}" in receipt

def test_get_receipt_empty_ingredients(self, bun):
# Проверка получения чека без ингредиентов.
burger = Burger()
burger.set_buns(bun)

receipt = burger.get_receipt()
assert BUN_BLACK in receipt
assert f"Price: {PRICE_200}" in receipt

def test_get_price_with_mocked_bun(self):
# Проверка расчета цены с использованием мока для булочки.
burger = Burger()
mock_bun = Mock()
mock_bun.get_price.return_value = PRICE_50
burger.set_buns(mock_bun)

price = burger.get_price()
assert price == PRICE_100 # Две булочки
mock_bun.get_price.assert_called()

def test_get_price_with_mocked_ingredients(self):
# Проверка расчета цены с использованием моков для ингредиентов.
burger = Burger()
bun = Bun(BUN_TEST, PRICE_100)
burger.set_buns(bun)

mock_ingredient = Mock()
mock_ingredient.get_price.return_value = PRICE_75
burger.add_ingredient(mock_ingredient)
burger.add_ingredient(mock_ingredient)

price = burger.get_price()
expected_price = PRICE_200 + PRICE_150 # 200 за булочки (100*2) + 150 за ингредиенты (75*2)
assert price == expected_price
assert mock_ingredient.get_price.call_count == 2

def test_remove_ingredient_with_invalid_index(self):
# Проверка удаления ингредиента с недопустимым индексом.
burger = Burger()
ingredient = Ingredient(INGREDIENT_TYPE_SAUCE, INGREDIENT_HOT_SAUCE, PRICE_100)
burger.add_ingredient(ingredient)

# Попытка удалить несуществующий индекс должна вызвать IndexError
with pytest.raises(IndexError) as excinfo:
burger.remove_ingredient(1)

assert isinstance(excinfo.value, IndexError)

def test_move_ingredient_with_invalid_indices(self):
# Проверка перемещения ингредиента с недопустимыми индексами.
burger = Burger()
ingredient = Ingredient(INGREDIENT_TYPE_SAUCE, INGREDIENT_HOT_SAUCE, PRICE_100)
burger.add_ingredient(ingredient)

# Попытка переместить несуществующий индекс должна вызвать IndexError
with pytest.raises(IndexError) as excinfo:
burger.move_ingredient(1, 0)

assert isinstance(excinfo.value, IndexError)

Loading