diff --git a/README.md b/README.md index 1cc701d..64658fd 100644 --- a/README.md +++ b/README.md @@ -1 +1,52 @@ -# qa_python \ No newline at end of file +# Юнит-тестирование BooksCollector + +Проект 4 спринта: покрытие тестами класса `BooksCollector`. + +## Описание реализованных тестов + +Файл `tests.py` содержит 11 тестов. + +### Добавление книг + +1. **test_add_new_book_adds_book_without_genre** + Проверяет, что при добавлении новой книги она появляется в словаре `books_genre`, а её жанр не задан (`None`). Используется параметризация по нескольким названиям. + +2. **test_add_new_book_does_not_add_book_with_name_longer_than_40** + Проверяет, что книга с названием длиннее 40 символов не добавляется в `books_genre`. + +3. **test_add_new_book_does_not_add_duplicate_book** + Проверяет, что одну и ту же книгу нельзя добавить в словарь больше одного раза. + +### Работа с жанрами + +4. **test_set_book_genre_sets_genre_for_existing_book** + Проверяет, что для существующей книги можно установить жанр из списка доступных. + +5. **test_set_book_genre_does_not_set_genre_for_unknown_book** + Проверяет, что для несуществующей книги жанр не устанавливается и она не добавляется в словарь. + +6. **test_get_book_genre_returns_none_for_book_without_genre** + Проверяет, что `get_book_genre` возвращает `None`, если жанр не установлен. + +7. **test_get_books_with_specific_genre_returns_only_books_with_that_genre** + Проверяет, что метод возвращает только книги с указанным жанром. + +8. **test_get_books_for_children_excludes_books_with_age_rating** + Проверяет, что книги с возрастным рейтингом не попадают в список доступных детям. + +### Избранное + +9. **test_add_book_in_favorites_adds_only_existing_book_and_ignores_duplicates** + Проверяет, что книгу можно добавить в избранное только один раз. + +10. **test_add_book_in_favorites_does_not_add_book_which_is_not_in_books_genre** + Проверяет, что нельзя добавить в избранное книгу, которой нет в `books_genre`. + +11. **test_delete_book_from_favorites_removes_book** + Проверяет, что книга удаляется из избранного. + +## Как запустить тесты + +```bash +pytest -v tests.py + diff --git a/main.py b/main.py index d3e0a17..dc74a03 100644 --- a/main.py +++ b/main.py @@ -22,36 +22,30 @@ def get_book_genre(self, name): # выводим список книг с определённым жанром def get_books_with_specific_genre(self, genre): - books_with_specific_genre = [] - if self.books_genre and genre in self.genre: - for name, book_genre in self.books_genre.items(): - if book_genre == genre: - books_with_specific_genre.append(name) - return books_with_specific_genre - - # получаем словарь books_genre - def get_books_genre(self): - return self.books_genre - - # возвращаем книги, подходящие детям + result = [] + for key, value in self.books_genre.items(): + if self.books_genre[key] == genre: + result.append(key) + return result + + # метод для детей: исключаем по возрастному рейтингу def get_books_for_children(self): - books_for_children = [] + result = [] for name, genre in self.books_genre.items(): - if genre not in self.genre_age_rating and genre in self.genre: - books_for_children.append(name) - return books_for_children + if genre not in self.genre_age_rating: + result.append(name) + return result - # добавляем книгу в Избранное + # добавляем в избранное def add_book_in_favorites(self, name): - if name in self.books_genre: - if name not in self.favorites: - self.favorites.append(name) + if name in self.books_genre and name not in self.favorites: + self.favorites.append(name) - # удаляем книгу из Избранного + # удаляем из избранного def delete_book_from_favorites(self, name): if name in self.favorites: self.favorites.remove(name) - # получаем список Избранных книг + # получаем список избранных книг def get_list_of_favorites_books(self): return self.favorites diff --git a/tests.py b/tests.py index 383385e..8bcede6 100644 --- a/tests.py +++ b/tests.py @@ -1,24 +1,169 @@ +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() +# ---------- Тесты для добавления книг ---------- - # добавляем две книги - collector.add_new_book('Гордость и предубеждение и зомби') - collector.add_new_book('Что делать, если ваш кот хочет вас убить') +@pytest.mark.parametrize('book_name', ['Книга 1', 'Очень важная книга']) +def test_add_new_book_adds_book_without_genre(book_name): + collector = BooksCollector() - # проверяем, что добавилось именно две - # словарь books_rating, который нам возвращает метод get_books_rating, имеет длину 2 - assert len(collector.get_books_rating()) == 2 + collector.add_new_book(book_name) + + books = collector.get_books_genre() + assert book_name in books + # у только что добавленной книги жанр — пустая строка + assert books[book_name] == '' + + +def test_add_new_book_does_not_add_book_with_name_longer_than_40(): + collector = BooksCollector() + long_name = 'А' * 41 # 41 символ + + collector.add_new_book(long_name) + + books = collector.get_books_genre() + assert long_name not in books + + +def test_add_new_book_does_not_add_duplicate_book(): + collector = BooksCollector() + book_name = 'Гарри Поттер' + + collector.add_new_book(book_name) + collector.add_new_book(book_name) + + books = collector.get_books_genre() + # одна и та же книга должна быть только один раз + assert list(books.keys()).count(book_name) == 1 + + +# ---------- Тесты для установки и получения жанра ---------- + +def test_set_book_genre_sets_genre_for_existing_book(): + collector = BooksCollector() + book_name = 'Безобидная книга' + collector.add_new_book(book_name) + + any_genre = collector.genre[0] + collector.set_book_genre(book_name, any_genre) + + assert collector.get_book_genre(book_name) == any_genre + + +def test_set_book_genre_does_not_set_genre_for_unknown_book(): + collector = BooksCollector() + unknown_book = 'Неизвестная книга' + any_genre = collector.genre[0] + + collector.set_book_genre(unknown_book, any_genre) + + books = collector.get_books_genre() + assert unknown_book not in books + + +def test_get_book_genre_returns_empty_string_for_book_without_genre(): + collector = BooksCollector() + book_name = 'Книга без жанра' + collector.add_new_book(book_name) + + assert collector.get_book_genre(book_name) == '' + + +# ---------- Тесты для получения книг по жанрам ---------- + +def test_get_books_with_specific_genre_returns_only_books_with_that_genre(): + collector = BooksCollector() + safe_genre = collector.genre[0] + other_genre = collector.genre[1] + + collector.add_new_book('Книга 1') + collector.set_book_genre('Книга 1', safe_genre) + + collector.add_new_book('Книга 2') + collector.set_book_genre('Книга 2', other_genre) + + books = collector.get_books_with_specific_genre(safe_genre) + + assert 'Книга 1' in books + assert 'Книга 2' not in books + + +def test_get_books_for_children_includes_safe_genre(): + collector = BooksCollector() + safe_genre = next( + genre for genre in collector.genre + if genre not in collector.genre_age_rating + ) + + collector.add_new_book('Детская книга') + collector.set_book_genre('Детская книга', safe_genre) + + children_books = collector.get_books_for_children() + + assert 'Детская книга' in children_books + + +def test_get_books_for_children_excludes_age_rating(): + collector = BooksCollector() + age_genre = collector.genre_age_rating[0] + + collector.add_new_book('Взрослая книга') + collector.set_book_genre('Взрослая книга', age_genre) + + children_books = collector.get_books_for_children() + + assert 'Взрослая книга' not in children_books + + +# ---------- Тесты для избранного ---------- + +def test_add_book_in_favorites_adds_only_existing_book_and_ignores_duplicates(): + collector = BooksCollector() + book_name = 'Любимая книга' + + collector.add_new_book(book_name) + + collector.add_book_in_favorites(book_name) + collector.add_book_in_favorites(book_name) # в избранном она должна остаться одна + + favorites = collector.get_list_of_favorites_books() + + assert book_name in favorites + assert favorites.count(book_name) == 1 + + +def test_add_book_in_favorites_does_not_add_book_which_is_not_in_books_genre(): + collector = BooksCollector() + unknown_book = 'Неизвестная книга' + + collector.add_book_in_favorites(unknown_book) + + favorites = collector.get_list_of_favorites_books() + assert unknown_book not in favorites + + +def test_delete_book_from_favorites_removes_book(): + collector = BooksCollector() + book_name = 'Книга для удаления' + + collector.add_new_book(book_name) + collector.add_book_in_favorites(book_name) + + collector.delete_book_from_favorites(book_name) + + favorites = collector.get_list_of_favorites_books() + assert book_name not in favorites + + +def test_get_list_of_favorites_books_returns_correct_list(): + collector = BooksCollector() + + 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() == ['Азбука', 'Алгебра'] - # напиши свои тесты ниже - # чтобы тесты были независимыми в каждом из них создавай отдельный экземпляр класса BooksCollector() \ No newline at end of file