diff --git a/README.md b/README.md index 1cc701d..8b5acea 100644 --- a/README.md +++ b/README.md @@ -1 +1,49 @@ -# qa_python \ No newline at end of file +# Тестирование приложения BooksCollector + +Проект содержит набор автотестов для проверки работоспособности приложения `BooksCollector`. Тесты написаны на языке **Python** с использованием фреймворка **pytest**. + +## Структура проекта + +* **`main.py`** — содержит исходный код класса `BooksCollector`. +* **`test.py`** — основной файл с тестами (класс `TestBooksCollector`). +* **`conftest.py`** — хранит общую фикстуру `collector_with_books`, которая автоматически подтягивается в тесты. +* **`books_data.py`** — содержит тестовые данные и параметры (например, список `BOOK_WITH_GENRE`), вынесенные из кода тестов. + + + +## Описание реализованных тестов + +### 1. Добавление книг в коллекцию (`add_new_book`) +* **test_add_new_book_add_two_books**: Проверка успешного добавления нескольких книг в пустую коллекцию. +* **test_add_new_book_ignore_duplicate_name**: Проверка того, что книга с уже существующим именем не добавляется повторно. +* **test_add_new_book_igonore_empty_name**: Проверка запрета на добавление книги с пустым названием. +* **test_add_new_book_igonore_book_name_longer_than_41_symblos**: Проверка граничного значения длины названия: книги с именами длиной 41 символ и более не добавляются. + +### 2. Установка и получение жанров (`set_book_genre`, `get_book_genre`) +* **test_set_book_genre**: (Параметризованный) Проверка корректной установки допустимого жанра для существующих книг. +* **test_set_book_genre_ignore_genre_not_in_list**: Проверка того, что жанр не устанавливается, если его нет в списке доступных (`self.genre`). +* **test_set_book_genre_ignore_book_not_in_collection**: Проверка того, что невозможно установить жанр книге, которой нет в коллекции. +* **test_get_book_genre_book_exist**: Проверка получения жанра для книги, которая есть в коллекции. +* **test_get_book_genre_book_not_exist**: Проверка, что при запросе жанра для отсутствующей книги возвращается `None`. + +### 3. Фильтрация и словари (`get_books_genre`, `get_books_with_specific_genre`) +* **test_get_books_genre_book_exist**: Проверка получения полного словаря `books_genre`. Тест подтверждает соответствие итогового словаря эталонному набору данных. +* **test_get_books_with_specific_genre**: (Параметризованный) Проверка фильтрации книг по конкретному жанру. Подтверждает, что метод возвращает список названий книг, соответствующих запросу. + +### 4. Детская библиотека (`get_books_for_children`) +* **test_get_books_for_children_only_children_genres**: Проверка корректной фильтрации книг для детей. Убеждаемся, что в список попадают только безопасные жанры без возрастного рейтинга. +* **test_get_books_for_children_no_children_genres**: (Параметризованный) Проверка исключения жанров "Ужасы" и "Детективы" из выдачи для детей. + +### 5. Работа с «Избранным» (`favorites`) +* **test_add_book_in_favorites_one_book**: Проверка успешного добавления книги в список избранного. +* **test_add_book_in_favorites_ignore_duplicates**: Проверка защиты от повторного добавления одной и той же книги в избранное. +* **test_delete_book_from_favorites_one_book**: Проверка удаления единственной книги из избранного. +* **test_delete_book_from_favorites_one_of_many**: Проверка точечного удаления: при удалении одной книги остальные должны остаться в списке. +* **test_delete_book_from_favorites_book_not_in_favorites**: Проверка того, что попытка удаления книги, которой нет в избранном, не вызывает ошибок и не меняет список. +* **test_get_list_of_favorites_books_return_favorites**: Проверка получения полного списка избранных книг. +* **test_get_list_of_favorites_books_empty_favorites**: Проверка работы метода при пустом списке избранного. + +## Технические особенности тестов +* **Фикстуры**: Применяется фикстура `collector_with_books` из `conftest.py` для быстрой предустановки объекта с набором данных. +* **Параметризация**: Используется `@pytest.mark.parametrize` с данными из `books_data.py`. +* **Множества (Set)**: Применяются для сравнения списков, где порядок элементов не имеет значения. \ No newline at end of file diff --git a/__pycache__/main.cpython-38.pyc b/__pycache__/main.cpython-38.pyc deleted file mode 100644 index 5786eeb..0000000 Binary files a/__pycache__/main.cpython-38.pyc and /dev/null differ diff --git a/__pycache__/test.cpython-38-pytest-7.1.2.pyc b/__pycache__/test.cpython-38-pytest-7.1.2.pyc deleted file mode 100644 index b2898a8..0000000 Binary files a/__pycache__/test.cpython-38-pytest-7.1.2.pyc and /dev/null differ diff --git a/books_data.py b/books_data.py new file mode 100644 index 0000000..712423a --- /dev/null +++ b/books_data.py @@ -0,0 +1,14 @@ +BOOK_WITH_GENRE = [ + ["Цветы для Элджернона", "Фантастика"], + ["Оно", "Ужасы"], + ["Убийство в Восточном экспрессе", "Детективы"], + ["Приключения Винни", "Мультфильмы"], + ["Горе от ума", "Комедии"] + ] + + +BOOK_FOR_CHILDREN = [ + "Цветы для Элджернона", + "Приключения Винни", + "Горе от ума" +] \ No newline at end of file diff --git a/conftest.py b/conftest.py new file mode 100644 index 0000000..acb0c1f --- /dev/null +++ b/conftest.py @@ -0,0 +1,17 @@ +import pytest +from main import BooksCollector +from books_data import BOOK_WITH_GENRE + + +# Фикстура для создания пустого эксземпляра BooksCollector +@pytest.fixture +def collector(): + return BooksCollector() + +# Фикстура для создания экземпляра BooksCollector с предзаполненными книгами и жанрами +@pytest.fixture +def collector_with_books(collector): + for name, genre in BOOK_WITH_GENRE: + collector.add_new_book(name) + collector.set_book_genre(name, genre) + return collector \ No newline at end of file diff --git a/test.py b/test.py new file mode 100644 index 0000000..c6b23c5 --- /dev/null +++ b/test.py @@ -0,0 +1,184 @@ +import pytest +from conftest import collector +from main import BooksCollector +from books_data import BOOK_WITH_GENRE +from books_data import BOOK_FOR_CHILDREN + +# класс TestBooksCollector объединяет набор тестов, которыми мы покрываем наше приложение BooksCollector +# обязательно указывать префикс Test +class TestBooksCollector: + + # пример теста: + # обязательно указывать префикс test_ + # дальше идет название метода, который тестируем add_new_book_п + # затем, что тестируем add_two_books - добавление двух книг + def test_add_new_book_add_two_books(self, collector): + # добавляем две книги + collector.add_new_book('Гордость и предубеждение и зомби') + collector.add_new_book('Что делать, если ваш кот хочет вас убить') + + # проверяем, что добавилось именно две + # словарь books_rating, который нам возвращает метод get_books_gengre, имеет длину 2 + assert len(collector.get_books_genre()) == 2 + + # Тест на проверку игнорирования дубликатов при добавлении книги + def test_add_new_book_ignore_duplicate_name(self, collector): + # Добавляем две книги с одинаковым именем + collector.add_new_book('Гордость и предубеждение и зомби') + collector.add_new_book('Гордость и предубеждение и зомби') + # Проверяем, что добавиласьь только одна книга + assert len(collector.get_books_genre()) == 1 + + # Тест на проверку игнорирования пустого имени при добавлении книги + def test_add_new_book_igonore_empty_name(self, collector): + # Добавляем книгу с пустым именем + collector.add_new_book("") + # Проверяем, что книга не добавилась + assert len(collector.get_books_genre()) == 0 + + # Тест на проверку игнорирования добавления книги с именем длинее 40 символа + def test_add_new_book_igonore_book_name_longer_than_41_symblos(self, collector): + # Создаем имя длиной 41 символа + name = "A" * 41 + # Добавляем книгу с именем длиной 41 символа + collector.add_new_book(name) + # # Проверяем, что книга не добавилась + assert len(collector.get_books_genre()) == 0 + + # Тест на проверку установки жанра книги черрез параметризацию + @pytest.mark.parametrize("book, genre", BOOK_WITH_GENRE) + def test_set_book_genre(self, collector, book, genre): + # Добавляем книгу + collector.add_new_book(book) + # Устанавливаем жанр книги + collector.set_book_genre(book, genre) + # Проверяем, что жанр книги установлен правильно + assert collector.get_book_genre(book) == genre + + # Тест на проверку игнорирования установки жанра книги не из списка жанров + def test_set_book_genre_ignore_genre_not_in_list(self, collector): + # Добавляем книгу + collector.add_new_book('Гордость и предубеждение и зомби') + # Добаляем жанр не из списка жанров + collector.set_book_genre('Гордость и предубеждение и зомби', 'Роман') + # Проверяем, что жанр книги не установлен + assert collector.get_book_genre('Гордость и предубеждение и зомби') == '' + + # Тест на проверку игнорирования установки жанра книги, которой нет в коллекции + def test_set_book_genre_ignore_book_not_in_collection(self, collector): + # Добавляем жанр книге, которой нет в коллекции + collector.set_book_genre('Гордость и предубеждение и зомби', 'Ужасы') + # Проверяем, что жанр книги не установлен + assert collector.get_book_genre('Гордость и предубеждение и зомби') is None + + # Тест на проверку получения жанра книги с фикстурой + def test_get_book_genre_book_exist(self, collector_with_books): + # Берем первую книгу и жанр из тестовых данных + book, genre = BOOK_WITH_GENRE[0] + # Проверяем, что жанр книги установлен корректно + assert collector_with_books.get_book_genre(book) == genre + + # Тест на проверку получения жанра книги, которой нет в коллекции, с фикстурой + def test_get_book_genre_book_not_exist(self, collector_with_books): + # Используем фикстуру с книгами и жанрами + assert collector_with_books.get_book_genre("Неизвестная книга") is None + + # Тест на проверку получения списка книг с определнным жанром черрез параметризацию + @pytest.mark.parametrize("book, genre", BOOK_WITH_GENRE) + def test_get_books_with_specific_genre(self, book, genre, collector_with_books): + # Проверяем, что книга возвращается в списке книг с определенным жанром + assert book in collector_with_books.get_books_with_specific_genre(genre) + + # Тест на проверку получения словаря books_genre + def test_get_books_genre_book_exist (self, collector_with_books): + # Преобразуем список книг с жанрами в словарь + dic_books = dict(BOOK_WITH_GENRE) + # Проверяем, что метод возвращает правильный словарь книг с жанрами + assert collector_with_books.get_books_genre() == dic_books + + # Тест на проверку получения списка книг, подходящих для детей + def test_get_books_for_children_only_children_genres(self, collector_with_books): + # Получаем список книг для детей + book_for_children = set(collector_with_books.get_books_for_children()) + # Проверяем, что в списке книг для детей только книги без возрастного рейтинга + assert book_for_children == set(BOOK_FOR_CHILDREN) + + # Тест на проверку получения списка книг, подходящих для детей, когда все книги имеют возрастной рейтинг + def test_get_books_for_children_no_children_genres(self, collector): + # Добавляем книгу с жанром из возрастного рейтинга + collector.add_new_book('Взрослая книга') + collector.set_book_genre('Взрослая книга', 'Ужасы') # можно выбрать любой из genre_age_rating + # Проверяем, что список книг для детей пустой + assert collector.get_books_for_children() == [] + + #Тест на проверку добавление книги в избранное + def test_add_book_in_favorites_one_book(self, collector): + # Добавляем новую книгу + collector.add_new_book("Приключения Винни") + # Добавляем книгу в избранное + collector.add_book_in_favorites("Приключения Винни") + # Проверяем, что книга добавлена в избраное + assert "Приключения Винни" in collector.get_list_of_favorites_books() + + #Тест на проверку игнорирования дубликатов при добавлении книги в избранное + def test_add_book_in_favorites_ignore_duplicates(self, collector): + # Добавляем новую книгу + collector.add_new_book("Приключения Винни") + # Добавляем книгу в избранное + collector.add_book_in_favorites("Приключения Винни") + collector.add_book_in_favorites("Приключения Винни") + # Проверяем, что книга добавлена в избраное + assert len(collector.get_list_of_favorites_books()) == 1 + + #Тест на проверку удаления книги из избранного + def test_delete_book_from_favorites_one_book(self, collector): + # Добавляем новую книгу + collector.add_new_book("Приключения Винни") + # Добавляем книгу в избранное + collector.add_book_in_favorites("Приключения Винни") + # Удаляем книгу из избранного + collector.delete_book_from_favorites("Приключения Винни") + # Проверяем, что книга удалена из избраного + assert "Приключения Винни" not in collector.get_list_of_favorites_books() + + #Тест на проверку удаления только одной книги из избранного при наличии нескольких книг + def test_delete_book_from_favorites_one_of_many(self, collector): + # Добавляем новую книгу + collector.add_new_book("Приключения Винни") + collector.add_new_book("Горе от ума") + # Добавляем книги в избранное + collector.add_book_in_favorites("Приключения Винни") + collector.add_book_in_favorites("Горе от ума") + # Удаляем одну книгу из избранного + collector.delete_book_from_favorites("Приключения Винни") + # Проверяем, что удалена только одна книга из избраного + assert collector.get_list_of_favorites_books() == ["Горе от ума"] + + # Тест на проверку не удаления книги из избранного, если ее там нет + def test_delete_book_from_favorites_book_not_in_favorites(self, collector): + # Добавляем новую книгу + collector.add_new_book("Приключения Винни") + # Добавляем книгу в избранное + collector.add_book_in_favorites("Приключения Винни") + # Пытаемся удалить книгу, которой нет в избранном + collector.delete_book_from_favorites("Горе от ума") + # Проверяем, что в избранном осталась только добавленная книга + assert collector.get_list_of_favorites_books() == ["Приключения Винни"] + + # Тест на проверку получения списка избранных книг + def test_get_list_of_favorites_books_return_favorites(self, collector): + # Добавляем новую книгу + collector.add_new_book("Приключения Винни") + collector.add_new_book("Горе от ума") + # Добавляем книги в избранное + collector.add_book_in_favorites("Приключения Винни") + collector.add_book_in_favorites("Горе от ума") + # Проверяем, что метод возвращает правильный список избранных книг + assert collector.get_list_of_favorites_books() == ["Приключения Винни", "Горе от ума"] + + # Тест на проверку получения списка избранных книг, когда избранное пусто + def test_get_list_of_favorites_books_empty_favorites(self, collector): + # Проверяем, что метод возвращает пустой список избранных книг + assert collector.get_list_of_favorites_books() == [] + + \ No newline at end of file diff --git a/tests.py b/tests.py deleted file mode 100644 index 383385e..0000000 --- a/tests.py +++ /dev/null @@ -1,24 +0,0 @@ -from main import BooksCollector - -# класс TestBooksCollector объединяет набор тестов, которыми мы покрываем наше приложение BooksCollector -# обязательно указывать префикс Test -class TestBooksCollector: - - # пример теста: - # обязательно указывать префикс test_ - # дальше идет название метода, который тестируем add_new_book_ - # затем, что тестируем add_two_books - добавление двух книг - def test_add_new_book_add_two_books(self): - # создаем экземпляр (объект) класса BooksCollector - collector = BooksCollector() - - # добавляем две книги - collector.add_new_book('Гордость и предубеждение и зомби') - collector.add_new_book('Что делать, если ваш кот хочет вас убить') - - # проверяем, что добавилось именно две - # словарь books_rating, который нам возвращает метод get_books_rating, имеет длину 2 - assert len(collector.get_books_rating()) == 2 - - # напиши свои тесты ниже - # чтобы тесты были независимыми в каждом из них создавай отдельный экземпляр класса BooksCollector() \ No newline at end of file