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
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
venv/
__pycache__/
*.pyc
.pytest_cache/
htmlcov/
.coverage
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,43 @@
**Запуск автотестов и создание HTML-отчета о покрытии**

> `$ pytest --cov=praktikum --cov-report=html`


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

# Запуск тестов с подробным выводом
pytest -v

# Запуск конкретного файла тестов
pytest tests/test_burger.py -v

# Запуск с отчетом о покрытии в консоли
pytest --cov=praktikum --cov-report=term-missing

Task 1: Юнит-тесты для Stellar Burgers

Установлены библиотеки:
pytest - для тестирования

pytest-cov - для измерения покрытия кода

Написаны тесты (43 теста):

Bun - тесты создания булочек, методов get_name(), get_price()
Ingredient - тесты ингредиентов (соусы/начинки), проверка типа, названия, цены
Burger - тесты конструктора бургеров (добавление/удаление ингредиентов, расчет стоимости, формирование чека)
Database - тесты базы данных (получение списков булочек и ингредиентов)

Использованы техники:

Параметризация - тесты с разными данными
Моки (Mock) - для изоляции зависимостей
Фикстуры - для подготовки тестовых данных

📊 Результаты:
43 теста - все проходят

Покрытие кода: 100%

Время выполнения: 0.14с
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pytest==7.4.0
pytest-cov==4.1.0
Empty file added tests/__init__.py
Empty file.
43 changes: 43 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import pytest
from unittest.mock import Mock
from praktikum.burger import Burger
from praktikum.bun import Bun
from praktikum.ingredient import Ingredient
from praktikum.ingredient_types import INGREDIENT_TYPE_SAUCE


@pytest.fixture
def sample_bun():
"""Фикстура для создания тестовой булочки."""
return Bun("test bun", 100)


@pytest.fixture
def sample_ingredient():
"""Фикстура для создания тестового ингредиента."""
return Ingredient(INGREDIENT_TYPE_SAUCE, "test sauce", 50)


@pytest.fixture
def burger():
"""Фикстура для создания бургера."""
return Burger()


@pytest.fixture
def mock_bun():
"""Фикстура для создания мока булочки."""
mock = Mock(spec=Bun)
mock.get_name.return_value = "test bun"
mock.get_price.return_value = 100
return mock


@pytest.fixture
def mock_ingredient():
"""Фикстура для создания мока ингредиента."""
mock = Mock(spec=Ingredient)
mock.get_name.return_value = "test ingredient"
mock.get_price.return_value = 50
mock.get_type.return_value = INGREDIENT_TYPE_SAUCE
return mock
34 changes: 34 additions & 0 deletions tests/test_bun.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import pytest
from praktikum.bun import Bun


class TestBun:

@pytest.mark.parametrize("name, price", [
("black bun", 100),
("white bun", 200),
("red bun", 300),
("Краторная булка N-200i", 1255),
("Флюоресцентная булка R2-D3", 988)
])
def test_bun_get_name(self, name, price):
"""Проверяем, что метод get_name возвращает правильное название булочки."""
bun = Bun(name, price)
assert bun.get_name() == name

@pytest.mark.parametrize("name, price", [
("black bun", 100),
("white bun", 200),
("red bun", 300),
("Краторная булка N-200i", 1255),
("Флюоресцентная булка R2-D3", 988)
])
def test_bun_get_price(self, name, price):
"""Проверяем, что метод get_price возвращает правильную цену булочки."""
bun = Bun(name, price)
assert bun.get_price() == price

def test_bun_creation_with_float_price(self):
"""Проверяем создание булочки с дробной ценой."""
bun = Bun("test bun", 99.99)
assert bun.get_price() == 99.99
127 changes: 127 additions & 0 deletions tests/test_burger.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import pytest
from unittest.mock import Mock
from praktikum.burger import Burger
from praktikum.bun import Bun
from praktikum.ingredient import Ingredient
from praktikum.ingredient_types import INGREDIENT_TYPE_SAUCE, INGREDIENT_TYPE_FILLING


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, mock_ingredient):
burger.add_ingredient(mock_ingredient)
assert len(burger.ingredients) == 1
assert burger.ingredients[0] == mock_ingredient

def test_remove_ingredient(self, burger, mock_ingredient):
burger.add_ingredient(mock_ingredient)
burger.remove_ingredient(0)
assert len(burger.ingredients) == 0

def test_move_ingredient(self, burger):
# Создаем два разных ингредиента
mock_ingredient1 = Mock(spec=Ingredient)
mock_ingredient1.get_name.return_value = "ingredient1"

mock_ingredient2 = Mock(spec=Ingredient)
mock_ingredient2.get_name.return_value = "ingredient2"

burger.add_ingredient(mock_ingredient1)
burger.add_ingredient(mock_ingredient2)

# Перемещаем первый ингредиент на место второго
burger.move_ingredient(0, 1)

# Проверяем, что порядок изменился
assert burger.ingredients[0] == mock_ingredient2
assert burger.ingredients[1] == mock_ingredient1

def test_get_price_with_bun_and_ingredients(self, burger, mock_bun, mock_ingredient):
burger.set_buns(mock_bun)
burger.add_ingredient(mock_ingredient)

# Цена: 2 булочки (100 * 2) + ингредиент (50) = 250
assert burger.get_price() == 250

def test_get_price_without_bun(self, burger, mock_ingredient):
burger.add_ingredient(mock_ingredient)

# Без булочки цена должна быть 0 + ингредиент (50)
# Но в текущей реализации будет ошибка при вызове bun.get_price()
# Это нужно протестировать
with pytest.raises(AttributeError):
burger.get_price()

def test_get_price_only_bun(self, burger, mock_bun):
burger.set_buns(mock_bun)
assert burger.get_price() == 200 # 100 * 2

def test_get_receipt(self, burger, mock_bun, mock_ingredient):
burger.set_buns(mock_bun)
burger.add_ingredient(mock_ingredient)

receipt = burger.get_receipt()

# Проверяем, что в чеке есть нужная информация
assert "test bun" in receipt
assert "test ingredient" in receipt
assert "250" in receipt # Общая цена
assert "=== test bun ===" in receipt
assert "Price: 250" in receipt

@pytest.mark.parametrize("ingredient_type, expected_type_str", [
(INGREDIENT_TYPE_SAUCE, "sauce"),
(INGREDIENT_TYPE_FILLING, "filling"),
("CUSTOM", "custom") # Для нестандартных типов
])
def test_get_receipt_with_different_ingredient_types(self, burger, mock_bun, ingredient_type, expected_type_str):
mock_ingredient = Mock(spec=Ingredient)
mock_ingredient.get_name.return_value = "test"
mock_ingredient.get_price.return_value = 100
mock_ingredient.get_type.return_value = ingredient_type

burger.set_buns(mock_bun)
burger.add_ingredient(mock_ingredient)

receipt = burger.get_receipt()
# Проверяем, что тип ингредиента в нижнем регистре есть в чеке
assert expected_type_str in receipt.lower()

def test_add_multiple_ingredients(self, burger, mock_bun):
burger.set_buns(mock_bun)

# Создаем несколько разных ингредиентов
for i in range(5):
mock_ingredient = Mock(spec=Ingredient)
mock_ingredient.get_price.return_value = i * 10
burger.add_ingredient(mock_ingredient)

assert len(burger.ingredients) == 5

def test_remove_ingredient_invalid_index(self, burger):
with pytest.raises(IndexError):
burger.remove_ingredient(0) # Пустой список

def test_move_ingredient_invalid_index(self, burger, mock_ingredient):
burger.add_ingredient(mock_ingredient)

with pytest.raises(IndexError):
burger.move_ingredient(1, 0) # Индекс 1 не существует

def test_get_price_empty_burger(self, burger):

with pytest.raises(AttributeError):
burger.get_price()

def test_get_receipt_empty_burger(self, burger):
with pytest.raises(AttributeError):
burger.get_receipt()

def test_move_ingredient_same_index(self, burger, mock_ingredient):
burger.add_ingredient(mock_ingredient)
burger.move_ingredient(0, 0) # Должно работать без ошибок
assert len(burger.ingredients) == 1
105 changes: 105 additions & 0 deletions tests/test_database.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import pytest
from unittest.mock import Mock, patch
from praktikum.database import Database
from praktikum.bun import Bun
from praktikum.ingredient import Ingredient


class TestDatabase:

@pytest.fixture
def database(self):
"""Фикстура для создания базы данных."""
return Database()

def test_database_initialization(self, database):
"""Проверяем инициализацию базы данных."""
assert database is not None
assert hasattr(database, 'buns')
assert hasattr(database, 'ingredients')

def test_available_buns(self, database):
"""Проверяем получение доступных булочек."""
buns = database.available_buns()

# Проверяем, что возвращается список
assert isinstance(buns, list)

# Проверяем количество булочек (из кода: 3 булочки)
assert len(buns) == 3

# Проверяем, что все элементы - экземпляры Bun
for bun in buns:
assert isinstance(bun, Bun)

# Проверяем названия булочек (из кода)
bun_names = [bun.get_name() for bun in buns]
assert "black bun" in bun_names
assert "white bun" in bun_names
assert "red bun" in bun_names

def test_available_ingredients(self, database):
"""Проверяем получение доступных ингредиентов."""
ingredients = database.available_ingredients()

# Проверяем, что возвращается список
assert isinstance(ingredients, list)

# Проверяем количество ингредиентов (из кода: 6 ингредиентов)
assert len(ingredients) == 6

# Проверяем, что все элементы - экземпляры Ingredient
for ingredient in ingredients:
assert isinstance(ingredient, Ingredient)

# Проверяем названия ингредиентов (из кода)
ingredient_names = [ingredient.get_name() for ingredient in ingredients]
assert "hot sauce" in ingredient_names
assert "sour cream" in ingredient_names
assert "chili sauce" in ingredient_names
assert "cutlet" in ingredient_names
assert "dinosaur" in ingredient_names
assert "sausage" in ingredient_names

def test_database_has_correct_bun_prices(self, database):
"""Проверяем цены булочек в базе данных."""
buns = database.available_buns()
prices = [bun.get_price() for bun in buns]
assert 100 in prices
assert 200 in prices
assert 300 in prices

def test_database_ingredient_types_correct(self, database):
"""Проверяем типы ингредиентов в базе данных."""
ingredients = database.available_ingredients()
types = [ing.get_type() for ing in ingredients]
assert "SAUCE" in types
assert "FILLING" in types

@patch('praktikum.database.Bun')
@patch('praktikum.database.Ingredient')
def test_database_with_mocks(self, MockIngredient, MockBun):
"""Тестируем базу данных с использованием моков."""
# Настраиваем моки
mock_bun = Mock()
mock_bun.get_name.return_value = "mock bun"
mock_bun.get_price.return_value = 999

mock_ingredient = Mock()
mock_ingredient.get_name.return_value = "mock ingredient"
mock_ingredient.get_price.return_value = 777
mock_ingredient.get_type.return_value = "SAUCE"

MockBun.return_value = mock_bun
MockIngredient.return_value = mock_ingredient

# Создаем базу данных с моками
db = Database()

# Проверяем, что Bun был вызван с правильными параметрами
assert MockBun.called

# Проверяем доступные булочки
buns = db.available_buns()
assert len(buns) > 0
assert buns[0] == mock_bun
Loading