-
Notifications
You must be signed in to change notification settings - Fork 0
Sprint_4 #8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Sprint_4 #8
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,104 @@ | ||
| # qa_python | ||
| # qa_python_4 | ||
| # Тестирование класса BooksCollector | ||
|
|
||
| ## Общая информация | ||
| - **Всего реализовано тестов:** 38 | ||
| - **Параметризированные тесты:** 2 (проверка граничных значений длины названия) | ||
| - **Покрытие методов:** 100% (все 10 методов класса протестированы) | ||
| - **Использование фикстур:** 4 фикстуры в conftest.py | ||
| - **Библиотека для тестирования:** pytest | ||
|
|
||
|
|
||
| ## Структура проекта | ||
|
|
||
|
|
||
| --- | ||
|
|
||
| ## Фикстуры (conftest.py) | ||
|
|
||
| | Фикстура | Описание | | ||
| |----------|----------| | ||
| | `collector` | Пустой экземпляр BooksCollector для каждого теста | | ||
| | `collector_with_books` | Экземпляр с 3 книгами без жанров | | ||
| | `collector_with_genres` | Экземпляр с книгами и установленными жанрами | | ||
| | `collector_with_favorites` | Экземпляр с книгами, жанрами и избранным | | ||
|
|
||
| --- | ||
|
|
||
| ## Группы тестов | ||
|
|
||
| ### Группа 1: Тестирование добавления книг (4 теста, включая 2 параметризированных) | ||
|
|
||
| | № | Название теста | Тип | Что проверяет | Ожидаемый результат | | ||
| |---|----------------|-----|----------------|---------------------| | ||
| | 1 | `test_add_new_book_add_two_books` | Обычный | Добавление нескольких книг | В словаре 2 книги | | ||
| | 2 | `test_add_new_book_with_invalid_length_not_added` | **Параметризированный** | Невалидные значения длины (пустая строка, >40 символов) | Книга не добавляется | | ||
| | 3 | `test_add_new_book_with_valid_length_added` | **Параметризированный** | Граничные значения валидной длины (1, 20, 40 символов) | Книга успешно добавляется | | ||
| | 4 | `test_add_new_book_duplicate_not_added` | Обычный | Добавление дубликата | Дубликат игнорируется | | ||
|
|
||
| ### Группа 2: Тестирование установки жанра (3 теста) | ||
|
|
||
| | № | Название теста | Что проверяет | Ожидаемый результат | | ||
| |---|----------------|----------------|---------------------| | ||
| | 5 | `test_set_book_genre` | Установка валидного жанра | Жанр успешно устанавливается | | ||
| | 6 | `test_set_book_genre_for_nonexistent_book` | Установка жанра несуществующей книге | Жанр не устанавливается | | ||
| | 7 | `test_set_book_genre_with_invalid_genre` | Установка невалидного жанра | Жанр не меняется (остаётся '') | | ||
|
|
||
| ### Группа 3: Тестирование получения жанра (3 теста) | ||
|
|
||
| | № | Название теста | Что проверяет | Ожидаемый результат | | ||
| |---|----------------|----------------|---------------------| | ||
| | 8 | `test_get_book_genre_for_nonexistent_book` | Получение жанра несуществующей книги | Возвращается None | | ||
| | 9 | `test_get_book_genre_for_existing_book` | Получение жанра существующей книги | Возвращается установленный жанр | | ||
| | 10 | `test_get_book_genre_for_book_without_genre` | Получение жанра книги без жанра | Возвращается '' | | ||
|
|
||
| ### Группа 4: Тестирование получения книг по жанрам (4 теста) | ||
|
|
||
| | № | Название теста | Что проверяет | Ожидаемый результат | | ||
| |---|----------------|----------------|---------------------| | ||
| | 11 | `test_get_books_with_specific_genre` | Получение книг конкретного жанра | Возвращаются только книги нужного жанра | | ||
| | 12 | `test_get_books_with_specific_genre_no_books` | Получение книг жанра, которого нет | Возвращается пустой список | | ||
| | 13 | `test_get_books_with_specific_genre_empty_collection` | Получение книг из пустой коллекции | Возвращается пустой список | | ||
| | 14 | `test_get_books_with_invalid_genre` | Получение книг с несуществующим жанром | Возвращается пустой список | | ||
|
|
||
| ### Группа 5: Тестирование метода get_books_genre (4 теста) | ||
|
|
||
| | № | Название теста | Что проверяет | Ожидаемый результат | | ||
| |---|----------------|----------------|---------------------| | ||
| | 15 | `test_get_books_genre_returns_dict` | Проверка типа возвращаемых данных | Возвращается словарь | | ||
| | 16 | `test_get_books_genre_empty_dict` | Получение пустого словаря | Возвращается {} | | ||
| | 17 | `test_get_books_genre_with_one_book` | Получение словаря с одной книгой | Словарь содержит 1 книгу без жанра | | ||
| | 18 | `test_get_books_genre_with_multiple_books` | Получение словаря с несколькими книгами | Словарь содержит все книги с их жанрами | | ||
|
|
||
| ### Группа 6: Тестирование книг для детей (3 теста) | ||
|
|
||
| | № | Название теста | Что проверяет | Ожидаемый результат | | ||
| |---|----------------|----------------|---------------------| | ||
| | 19 | `test_get_books_for_children` | Книги с возрастным рейтингом не попадают в список для детей | В списке только книги без возрастных ограничений | | ||
| | 20 | `test_get_books_for_children_without_genre` | Книги без жанра не попадают в список для детей | Книга без жанра отсутствует в списке | | ||
| | 21 | `test_get_books_for_children_empty` | Получение списка из пустой коллекции | Возвращается пустой список | | ||
|
|
||
| ### Группа 7: Тестирование избранного (9 тестов) | ||
|
|
||
| | № | Название теста | Что проверяет | Ожидаемый результат | | ||
| |---|----------------|----------------|---------------------| | ||
| | 22 | `test_add_book_in_favorites` | Добавление книги в избранное | Книга появляется в избранном | | ||
| | 23 | `test_add_nonexistent_book_to_favorites` | Добавление несуществующей книги в избранное | Книга не добавляется | | ||
| | 24 | `test_add_duplicate_book_to_favorites` | Добавление дубликата в избранное | Дубликат игнорируется | | ||
| | 25 | `test_delete_book_from_favorites` | Удаление книги из избранного | Книга удаляется | | ||
| | 26 | `test_delete_nonexistent_book_from_favorites` | Удаление несуществующей книги из избранного | Ничего не происходит | | ||
| | 27 | `test_delete_book_from_favorites_not_in_favorites` | Удаление книги, которой нет в избранном | Ничего не происходит | | ||
| | 28 | `test_get_list_of_favorites_books_empty` | Получение пустого списка избранного | Возвращается пустой список | | ||
| | 29 | `test_get_list_of_favorites_books_returns_list` | Проверка типа возвращаемых данных | Возвращается список | | ||
| | 30 | `test_get_list_of_favorites_books_with_one_book` | Получение списка с одной книгой | Список содержит 1 книгу | | ||
| | 31 | `test_get_list_of_favorites_books_with_multiple_books` | Получение списка с несколькими книгами | Список содержит все добавленные книги | | ||
|
|
||
|
|
||
|
|
||
| --- | ||
|
|
||
| ### Тест 1: Невалидные значения длины названия | ||
| test_add_new_book_with_invalid_length_not_added | ||
| ### Тест 2: Валидные значения длины названия (граничные значения) | ||
| test_add_new_book_with_valid_length_added | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| import pytest | ||
| from books_collector import BooksCollector | ||
|
|
||
| @pytest.fixture | ||
| def collector(): | ||
| """Фикстура, возвращающая новый экземпляр BooksCollector для каждого теста""" | ||
| return BooksCollector() | ||
|
|
||
| @pytest.fixture | ||
| def collector_with_books(collector): | ||
| """Фикстура с предустановленными книгами""" | ||
| books = ['Книга 1', 'Книга 2', 'Книга 3'] | ||
| for book in books: | ||
| collector.add_new_book(book) | ||
| return collector | ||
|
|
||
| @pytest.fixture | ||
| def collector_with_genres(collector_with_books): | ||
| """Фикстура с книгами и жанрами""" | ||
| collector = collector_with_books | ||
| collector.set_book_genre('Книга 1', 'Фантастика') | ||
| collector.set_book_genre('Книга 2', 'Ужасы') | ||
| collector.set_book_genre('Книга 3', 'Детективы') | ||
| return collector | ||
|
|
||
| @pytest.fixture | ||
| def collector_with_favorites(collector_with_genres): | ||
| """Фикстура с книгами, жанрами и избранным""" | ||
| collector = collector_with_genres | ||
| collector.add_book_in_favorites('Книга 1') | ||
| collector.add_book_in_favorites('Книга 2') | ||
| return collector |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,24 +1,162 @@ | ||
| import pytest | ||
| 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() | ||
|
|
||
| # добавляем две книги | ||
| # Тесты добавления книг | ||
| def test_add_new_book_add_two_books(self, collector): | ||
| collector.add_new_book('Гордость и предубеждение и зомби') | ||
| collector.add_new_book('Что делать, если ваш кот хочет вас убить') | ||
| assert len(collector.get_books_genre()) == 2 | ||
|
|
||
| @pytest.mark.parametrize('invalid_name', [ | ||
| '', | ||
| 'А' * 41, | ||
| 'А' * 100, | ||
| ]) | ||
| def test_add_new_book_with_invalid_length_not_added(self, collector, invalid_name): | ||
| collector.add_new_book(invalid_name) | ||
| assert len(collector.get_books_genre()) == 0 | ||
|
|
||
| @pytest.mark.parametrize('valid_name', [ | ||
| 'А', | ||
| 'А' * 20, | ||
| 'А' * 40, | ||
| 'Книга с пробелами и знаками препинания!', | ||
| ]) | ||
| def test_add_new_book_with_valid_length_added(self, collector, valid_name): | ||
| collector.add_new_book(valid_name) | ||
| assert len(collector.get_books_genre()) == 1 | ||
| assert valid_name in collector.get_books_genre() | ||
|
|
||
| def test_add_new_book_duplicate_not_added(self, collector): | ||
| collector.add_new_book('Книга') | ||
| collector.add_new_book('Книга') | ||
| assert len(collector.get_books_genre()) == 1 | ||
|
|
||
| # Тесты установки и получения жанра | ||
| def test_set_book_genre(self, collector): | ||
| book_name = 'Книга' | ||
| collector.add_new_book(book_name) | ||
| collector.set_book_genre(book_name, 'Ужасы') | ||
| assert collector.get_book_genre(book_name) == 'Ужасы' | ||
|
|
||
| def test_set_book_genre_for_nonexistent_book(self, collector): | ||
| collector.set_book_genre('Несуществующая книга', 'Фантастика') | ||
| assert collector.get_book_genre('Несуществующая книга') is None | ||
|
|
||
| def test_set_book_genre_with_invalid_genre(self, collector): | ||
| book_name = 'Книга' | ||
| collector.add_new_book(book_name) | ||
| collector.set_book_genre(book_name, 'Неверный жанр') | ||
| assert collector.get_book_genre(book_name) == '' | ||
|
|
||
| def test_get_book_genre_for_nonexistent_book(self, collector): | ||
| assert collector.get_book_genre('Несуществующая книга') is None | ||
|
|
||
| def test_get_book_genre_for_existing_book(self, collector): | ||
| book_name = 'Книга' | ||
| collector.add_new_book(book_name) | ||
| collector.set_book_genre(book_name, 'Фантастика') | ||
| assert collector.get_book_genre(book_name) == 'Фантастика' | ||
|
|
||
| def test_get_book_genre_for_book_without_genre(self, collector): | ||
| book_name = 'Книга без жанра' | ||
| collector.add_new_book(book_name) | ||
| assert collector.get_book_genre(book_name) == '' | ||
|
|
||
| # Тесты получения книг по жанрам | ||
| def test_get_books_with_specific_genre(self, collector_with_genres): | ||
| horror_books = collector_with_genres.get_books_with_specific_genre('Ужасы') | ||
| assert len(horror_books) == 1 | ||
| assert 'Книга 2' in horror_books | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Можно лучше: не стоит хранить одно и то же тестовое значение отдельно - если что-то было создано в фикстуре, то тут стоит вызвать это значение, а не дублировать его. Иначе тесты станут неподдерживаемыми - легко изменить что то в фикстуре (например) и не заметить что и в тесте тоже нужно поменять. Так как сейчас эти данные не связаны, но должны быть. Удачное решение - создать файл с тестовыми данными и обращаться к нему и в фикстуре и в тестах |
||
|
|
||
| def test_get_books_with_specific_genre_no_books(self, collector): | ||
| assert collector.get_books_with_specific_genre('Ужасы') == [] | ||
|
|
||
| def test_get_books_with_specific_genre_empty_collection(self, collector): | ||
| result = collector.get_books_with_specific_genre('Фантастика') | ||
| assert result == [] | ||
|
|
||
| def test_get_books_with_invalid_genre(self, collector_with_genres): | ||
| assert collector_with_genres.get_books_with_specific_genre('Неверный жанр') == [] | ||
|
|
||
| # Тесты метода get_books_genre | ||
| def test_get_books_genre_returns_dict(self, collector): | ||
| result = collector.get_books_genre() | ||
| assert isinstance(result, dict) | ||
|
|
||
| def test_get_books_genre_empty_dict(self, collector): | ||
| assert collector.get_books_genre() == {} | ||
|
|
||
| def test_get_books_genre_with_one_book(self, collector): | ||
| collector.add_new_book('Книга 1') | ||
| books = collector.get_books_genre() | ||
| assert len(books) == 1 | ||
| assert 'Книга 1' in books | ||
| assert books['Книга 1'] == '' | ||
|
|
||
| def test_get_books_genre_with_multiple_books(self, collector_with_genres): | ||
| books = collector_with_genres.get_books_genre() | ||
| assert len(books) == 3 | ||
| assert books['Книга 1'] == 'Фантастика' | ||
| assert books['Книга 2'] == 'Ужасы' | ||
| assert books['Книга 3'] == 'Детективы' | ||
|
|
||
| # Тесты книг для детей | ||
| def test_get_books_for_children(self, collector_with_genres): | ||
| children_books = collector_with_genres.get_books_for_children() | ||
| assert len(children_books) == 1 | ||
| assert 'Книга 1' in children_books # Фантастика - для детей | ||
| assert 'Книга 2' not in children_books # Ужасы - не для детей | ||
| assert 'Книга 3' not in children_books # Детективы - не для детей | ||
|
|
||
| def test_get_books_for_children_without_genre(self, collector): | ||
| collector.add_new_book('Книга без жанра') | ||
| children_books = collector.get_books_for_children() | ||
| assert 'Книга без жанра' not in children_books | ||
|
|
||
| def test_get_books_for_children_empty(self, collector): | ||
| assert collector.get_books_for_children() == [] | ||
|
|
||
| # Тесты избранного | ||
| def test_add_book_in_favorites(self, collector_with_books): | ||
| collector_with_books.add_book_in_favorites('Книга 1') | ||
| assert 'Книга 1' in collector_with_books.get_list_of_favorites_books() | ||
|
|
||
| def test_add_nonexistent_book_to_favorites(self, collector): | ||
| collector.add_book_in_favorites('Несуществующая книга') | ||
| assert len(collector.get_list_of_favorites_books()) == 0 | ||
|
|
||
| def test_add_duplicate_book_to_favorites(self, collector_with_books): | ||
| collector_with_books.add_book_in_favorites('Книга 1') | ||
| collector_with_books.add_book_in_favorites('Книга 1') | ||
| assert len(collector_with_books.get_list_of_favorites_books()) == 1 | ||
|
|
||
| def test_delete_book_from_favorites(self, collector_with_favorites): | ||
| collector_with_favorites.delete_book_from_favorites('Книга 1') | ||
| assert 'Книга 1' not in collector_with_favorites.get_list_of_favorites_books() | ||
| assert 'Книга 2' in collector_with_favorites.get_list_of_favorites_books() | ||
|
|
||
| def test_delete_nonexistent_book_from_favorites(self, collector_with_favorites): | ||
| collector_with_favorites.delete_book_from_favorites('Несуществующая книга') | ||
| assert len(collector_with_favorites.get_list_of_favorites_books()) == 2 | ||
|
|
||
| def test_get_list_of_favorites_books_empty(self, collector): | ||
| assert collector.get_list_of_favorites_books() == [] | ||
|
|
||
| def test_get_list_of_favorites_books_returns_list(self, collector): | ||
| favorites = collector.get_list_of_favorites_books() | ||
| assert isinstance(favorites, list) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Нужно исправить: отсутствуют тесты на проверку методов get_books_genre. На каждый метод должен быть отдельный тест, вне зависимости, вызывается он в других тестах или нет |
||
|
|
||
| # проверяем, что добавилось именно две | ||
| # словарь books_rating, который нам возвращает метод get_books_rating, имеет длину 2 | ||
| assert len(collector.get_books_rating()) == 2 | ||
| def test_get_list_of_favorites_books_with_one_book(self, collector_with_books): | ||
| collector_with_books.add_book_in_favorites('Книга 1') | ||
| favorites = collector_with_books.get_list_of_favorites_books() | ||
| assert len(favorites) == 1 | ||
| assert 'Книга 1' in favorites | ||
|
|
||
| # напиши свои тесты ниже | ||
| # чтобы тесты были независимыми в каждом из них создавай отдельный экземпляр класса BooksCollector() | ||
| def test_get_list_of_favorites_books_with_multiple_books(self, collector_with_favorites): | ||
| favorites = collector_with_favorites.get_list_of_favorites_books() | ||
| assert len(favorites) == 2 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Нужно исправить: согласно заданию необходимо создать как минимум один параметризированный тест. В данном задании для параметризации лучше всего подходят граничные значения в классе длины имени - отдельно невалидные значения и отдельным тестом - ГЗ для валидных |
||
| assert 'Книга 1' in favorites | ||
| assert 'Книга 2' in favorites | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
нужно исправить: почему в ридми лежит код тестов?