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
68 changes: 68 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

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

Expand Down
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.
Empty file added tests/__init__.py
Empty file.
27 changes: 27 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -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
Comment on lines +10 to +11

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Можно лучше: во всех тестах лучше выносить тестовые данные во внешний модуль (например, data). Это позволит облегчить их поддержку

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()
83 changes: 83 additions & 0 deletions tests/data.py
Original file line number Diff line number Diff line change
@@ -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
80 changes: 80 additions & 0 deletions tests/test_burger.py
Original file line number Diff line number Diff line change
@@ -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()