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
57 changes: 57 additions & 0 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: Unit Tests

on:
push:
branches: [ "main", "develop1" ]
pull_request:
branches: [ "main", "develop1" ]

permissions:
contents: write

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.13"

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt

- name: Run Unit tests with Coverage
run: pytest --cov=praktikum --cov-report=term-missing
continue-on-error: true

- name: Get Allure history
uses: actions/checkout@v4
if: always()
continue-on-error: true
with:
ref: gh-pages
path: gh-pages

- name: Allure Report Action
uses: simple-elf/allure-report-action@master
if: always()
with:
allure_results: allure-results
allure_history: allure-history
keep_reports: 20

- name: Deploy report to Github Pages
if: always()
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: allure-history
publish_branch: gh-pages
force_orphan: true
165 changes: 165 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
### Python template
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
.pybuilder/
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock

# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
.pdm.toml
.pdm-python
.pdm-build/

# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# pytype static type analyzer
.pytype/

# Cython debug symbols
cython_debug/

# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
.idea/
allure-results/
allure-report/
131 changes: 119 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,131 @@
## Задание 1: Юнит-тесты
# 🍔 Stellar Burgers: Unit Testing Framework (Part 1)

### Автотесты для проверки программы, которая помогает заказать бургер в Stellar Burgers
![CI/CD Status](https://github.com/AlyaSmirnova/Diplom_1/actions/workflows/unit-tests.yml/badge.svg?branch=main)
[![Python Version](https://img.shields.io/badge/python-3.11-blue)](https://www.python.org)
[![Coverage](https://img.shields.io/badge/Coverage-90%25-brightgreen)](https://github.com)
[![Tests](https://img.shields.io/badge/Tests-Pytest-blue?logo=pytest\&logoColor=white)](https://docs.pytest.org/)
[![Reports](https://img.shields.io/badge/Reports-Allure-orange?logo=allure)](https://github.com)

### Реализованные сценарии
## ✅ Table of Contents
1. [Description](#-description)
2. [Tech Stack & Tools](#-tech-stack-&-tools)
3. [Project Architecture](#-project-architecture)
4. [Allure Reporting Features](#-allure-reporting-features)
5. [Test Coverage](#-test-coverage)
6. [Execution Guide](#-execution-guide)
7. [CI/CD Workflow](#-cicd-workflow)

Созданы юнит-тесты, покрывающие классы `Bun`, `Burger`, `Ingredient`, `Database`
## 💫 Description
This is the first part of the graduation project: a comprehensive **Unit Testing** suite for the **Stellar Burgers** application.
The goal of this framework is to ensure the reliability of core business logic, including burger assembly, ingredient management, and price calculation, achieving **100% code coverage**.

Процент покрытия 100% (отчет: `htmlcov/index.html`)
## Tech Stack & Tools
- **Language:** Python 3.13+
- **Testing Framework:** [Pytest](https://docs.pytest.org/)
- **Isolation:** [Unittest.Mock](https://docs.python.org) (for mocking dependencies)
- **Coverage Tool:** [Pytest-cov](https://pypi.org/project/pytest-cov/)
- **Reporting:** Allure Framework
- **CI/CD:** GitHub Actions

### Структура проекта
## Project Architecture
```text
Diplom_1/
├── .github/workflows/ # CI/CD pipeline configuration
├── allure-results/ # Raw test execution data (generated after run)
├── praktikum # Source code (Business logic)
│ ├── burger.py
│ ├── database.py
│ ├── ingredient.py
│ ├── ingredient_types.py
│ ├── order_queue_page.py
├── tests/ # Unit test scenarios
│ ├── test_bun.py
│ ├── test_burger.py
│ ├── test_database.py
│ ├── test_ingredient.py
├── conftest.py # Fixtures
├── pytest.ini # Pytest & Allure configuration
├── requirements.txt # Project dependencies
└── README.md # Comprehensive project documentation
```

- `praktikum` - пакет, содержащий код программы
- `tests` - пакет, содержащий тесты, разделенные по классам. Например, `bun_test.py`, `burger_test.py` и т.д.
## 📊 Allure Reporting Features
The project is integrated with the **Allure Framework** to provide high-level visibility into the unit testing process. Key features include:

### Запуск автотестов
* **Class-Based Grouping:** Tests are logically organized by **Features** corresponding to core classes (`Bun`, `Ingredient`, `Burger`, `Database`), making it easy to navigate the test suite.
* **Dynamic Documentation:** Uses `@allure.title` and `@allure.description` to transform technical test methods into clear, readable business requirements.
* **Execution Transparency:** Detailed logging for complex assembly logic in the `Burger` class, ensuring that every step of the burger construction is tracked.
* **Validation Details:** Comprehensive error messages and attribute verification are captured in the report, simplifying the debugging process.
* **Scalable Reporting:** Ready for integration with CI/CD tools to track test history and stability over time.

**Установка зависимостей**
## 🧪 Test Coverage
The suite provides **100% code coverage** for the core logic of the **Stellar Burgers** application, ensuring every method and boundary case is validated:

### 1. Bun Class
* **Constructor Validation:** Ensuring the name and price are set correctly and have the proper data types (`str` and `float`).
* **Method Verification:** Testing `get_name()` and `get_price()` for accurate data retrieval.

### 2. Ingredient Class
* **Initialization:** Verifying the correct assignment of ingredient types (Sauce/Filling), names, and prices.
* **Getters Testing:** Confirming that `get_name()`, `get_price()`, and `get_type()` return the expected values.

### 3. Burger Class (Complex Logic & Mocking)
* **Assembly Operations:**
* Successful addition and removal of ingredients using **Mock objects** to isolate tests from the `Ingredient` class.
* Verification of the `move_ingredient()` method to ensure correct reordering within the list.
* **Pricing Engine:** Testing `get_price()` with **Mocking** and **Patching** to verify the calculation formula: `(Bun Price * 2) + Sum of Ingredients`.
* **Receipt Generation:** Validating the output format of the `get_receipt()` method, ensuring all components are displayed correctly in the final string.

### 4. Database Class
* **Data Integrity:** Verification that the database returns the correct pre-defined list of 3 buns and 6 ingredients.
* **List Validation:** Checking that `available_buns()` and `available_ingredients()` return lists of the expected size and content.

## 🚀 Execution Guide

### 1. Environment Setup
Clone the repository and set up a local virtual environment to ensure dependency isolation:

1. **Clone repository**
> ```bash
> git clone https://github.com/AlyaSmirnova/Diplom_1
> cd Diplom_1
📦 Repository: [Sprint_5](https://github.com/AlyaSmirnova/Diplom_1)

2. **Create a virtual environment**
> ```bash
> python -m venv venv

3. **Activate the virtual environment**
> ```bash
> source venv/bin/activate

4. **Install required dependencies**
> `$ pip install -r requirements.txt`

**Запуск автотестов и создание HTML-отчета о покрытии**
### 2. Running Tests
The framework is pre-configured via `pytest.ini`. You can execute the full test suite with a single command:
> ```bash
> pytest

### 3. Code Coverage Analysis
To verify that the tests provide 100% code coverage, run the following command:
> ```bash
> pytest --cov=praktikum --cov-report=term-missing

### 4. Generating Allure Report
To transform the test results into a visual, interactive HTML report:
> ```bash
> allure serve allure-results

## ⚙️ CI/CD Workflow
The project is fully automated using **GitHub Actions**. Upon every `push` to the **main** branch or any `Pull Request` creation:

1. **Environment Provisioning:** A clean **Ubuntu** runner is initialized in the cloud environment.
2. **Dependency Management:** The Python **3.13** environment is set up, and all required libraries (`Pytest`, `Pytest-cov`, `Allure`) are installed from `requirements.txt`.
3. **Automated Unit Testing:** Execution of the full test suite to ensure that all core business logic functions correctly.
4. **Coverage Analysis:** Automated check of **Code Coverage** (100% target) to ensure no untested logic reaches the repository.
5. **Allure Artifact Generation:** Test results and execution logs are collected to prepare a comprehensive **Allure report**.
6. **Status Badges:** Real-time feedback on build success and coverage percentage is provided via GitHub status badges.

> `$ pytest --cov=praktikum --cov-report=html`
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"name": "Successfully create an ingredient and verify attributes", "status": "passed", "start": 1773492481787, "stop": 1773492481787, "uuid": "d67a1175-de0e-49ce-a3f7-01329c19d61d", "historyId": "5b9a54ac28f62363619a289e19c604aa", "testCaseId": "5b9a54ac28f62363619a289e19c604aa", "fullName": "tests.test_ingredient.TestIngredient#test_create_ingredient_is_successfil", "labels": [{"name": "feature", "value": "Ingredient Logic"}, {"name": "parentSuite", "value": "tests"}, {"name": "suite", "value": "test_ingredient"}, {"name": "subSuite", "value": "TestIngredient"}, {"name": "host", "value": "MacBook-Pro-Alina.local"}, {"name": "thread", "value": "71332-MainThread"}, {"name": "framework", "value": "pytest"}, {"name": "language", "value": "cpython3"}, {"name": "package", "value": "tests.test_ingredient"}], "titlePath": ["tests", "test_ingredient.py", "TestIngredient"]}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"name": "Remove ingredient successfully using Mock", "status": "passed", "start": 1773492481759, "stop": 1773492481759, "uuid": "58138ec2-9d34-446a-88b2-1b3d9cb86c3c", "historyId": "ee8f1f7603ffc3a6583ba1185f330531", "testCaseId": "ee8f1f7603ffc3a6583ba1185f330531", "fullName": "tests.test_burger.TestBurger#test_remove_ingredient_as_mock_success", "labels": [{"name": "feature", "value": "Burger Operations"}, {"name": "parentSuite", "value": "tests"}, {"name": "suite", "value": "test_burger"}, {"name": "subSuite", "value": "TestBurger"}, {"name": "host", "value": "MacBook-Pro-Alina.local"}, {"name": "thread", "value": "71332-MainThread"}, {"name": "framework", "value": "pytest"}, {"name": "language", "value": "cpython3"}, {"name": "package", "value": "tests.test_burger"}], "titlePath": ["tests", "test_burger.py", "TestBurger"]}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"uuid": "1d7c5007-cc66-4e6f-a3ea-c719ba1e85c2", "befores": [{"name": "index", "status": "passed", "start": 1773492481783, "stop": 1773492481783}], "start": 1773492481783, "stop": 1773492481783}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"name": "Check get_price() method returns correct value", "status": "passed", "start": 1773492481746, "stop": 1773492481746, "uuid": "2ad3419b-49f4-458b-b631-add0a1151479", "historyId": "33c15517578a45ce5714eace7a5b1a6c", "testCaseId": "33c15517578a45ce5714eace7a5b1a6c", "fullName": "tests.test_bun.TestBun#test_get_price_returns_correct_value", "labels": [{"name": "feature", "value": "Bun"}, {"name": "parentSuite", "value": "tests"}, {"name": "suite", "value": "test_bun"}, {"name": "subSuite", "value": "TestBun"}, {"name": "host", "value": "MacBook-Pro-Alina.local"}, {"name": "thread", "value": "71332-MainThread"}, {"name": "framework", "value": "pytest"}, {"name": "language", "value": "cpython3"}, {"name": "package", "value": "tests.test_bun"}], "titlePath": ["tests", "test_bun.py", "TestBun"]}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"uuid": "87276cd3-001a-461f-ab87-005407c9ebae", "children": ["1377addc-05a3-443a-ac13-cd0d940408dc"], "befores": [{"name": "expected_ingredients", "status": "passed", "start": 1773492481785, "stop": 1773492481785}], "start": 1773492481785, "stop": 1773492481786}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"name": "Set bun using Mock object", "status": "passed", "start": 1773492481751, "stop": 1773492481752, "uuid": "739a7025-71da-46ae-9a87-c8a025f3520b", "historyId": "6dd204c147380aee1cfc63563f8edb8c", "testCaseId": "6dd204c147380aee1cfc63563f8edb8c", "fullName": "tests.test_burger.TestBurger#test_set_buns_return_correct_bun", "labels": [{"name": "feature", "value": "Burger Operations"}, {"name": "parentSuite", "value": "tests"}, {"name": "suite", "value": "test_burger"}, {"name": "subSuite", "value": "TestBurger"}, {"name": "host", "value": "MacBook-Pro-Alina.local"}, {"name": "thread", "value": "71332-MainThread"}, {"name": "framework", "value": "pytest"}, {"name": "language", "value": "cpython3"}, {"name": "package", "value": "tests.test_burger"}], "titlePath": ["tests", "test_burger.py", "TestBurger"]}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"name": "Verify get_receipt() formatting", "status": "passed", "start": 1773492481767, "stop": 1773492481767, "uuid": "9ebc7b36-771d-4d65-abb9-d8cdc5e61073", "historyId": "5bf52d3a38b900560c9be02b6a5d981c", "testCaseId": "5bf52d3a38b900560c9be02b6a5d981c", "fullName": "tests.test_burger.TestBurger#test_get_receipt", "labels": [{"name": "feature", "value": "Burger Operations"}, {"name": "parentSuite", "value": "tests"}, {"name": "suite", "value": "test_burger"}, {"name": "subSuite", "value": "TestBurger"}, {"name": "host", "value": "MacBook-Pro-Alina.local"}, {"name": "thread", "value": "71332-MainThread"}, {"name": "framework", "value": "pytest"}, {"name": "language", "value": "cpython3"}, {"name": "package", "value": "tests.test_burger"}], "titlePath": ["tests", "test_burger.py", "TestBurger"]}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"name": "Verify get_name() returns the correct value", "status": "passed", "start": 1773492481789, "stop": 1773492481789, "uuid": "be972ca3-8327-4813-9885-631520777a82", "historyId": "1bc7a4eb2b1d02efe05268fa0181c788", "testCaseId": "1bc7a4eb2b1d02efe05268fa0181c788", "fullName": "tests.test_ingredient.TestIngredient#test_get_name_return_correct_name", "labels": [{"name": "feature", "value": "Ingredient Logic"}, {"name": "parentSuite", "value": "tests"}, {"name": "suite", "value": "test_ingredient"}, {"name": "subSuite", "value": "TestIngredient"}, {"name": "host", "value": "MacBook-Pro-Alina.local"}, {"name": "thread", "value": "71332-MainThread"}, {"name": "framework", "value": "pytest"}, {"name": "language", "value": "cpython3"}, {"name": "package", "value": "tests.test_ingredient"}], "titlePath": ["tests", "test_ingredient.py", "TestIngredient"]}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"uuid": "6086fab3-a092-4661-a5e3-8b6c089daf2f", "befores": [{"name": "index", "status": "passed", "start": 1773492481771, "stop": 1773492481771}], "start": 1773492481771, "stop": 1773492481771}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"name": "Add ingredient successfully using Mock", "status": "passed", "start": 1773492481757, "stop": 1773492481757, "uuid": "8e396983-ae1d-43dd-9034-6933d31a85b9", "historyId": "470e54296e45b428ad46af4f711515b2", "testCaseId": "470e54296e45b428ad46af4f711515b2", "fullName": "tests.test_burger.TestBurger#test_add_ingredient_as_mock_success", "labels": [{"name": "feature", "value": "Burger Operations"}, {"name": "parentSuite", "value": "tests"}, {"name": "suite", "value": "test_burger"}, {"name": "subSuite", "value": "TestBurger"}, {"name": "host", "value": "MacBook-Pro-Alina.local"}, {"name": "thread", "value": "71332-MainThread"}, {"name": "framework", "value": "pytest"}, {"name": "language", "value": "cpython3"}, {"name": "package", "value": "tests.test_burger"}], "titlePath": ["tests", "test_burger.py", "TestBurger"]}
Loading