-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_sqlite_task.py
More file actions
238 lines (200 loc) · 11.5 KB
/
Copy pathtest_sqlite_task.py
File metadata and controls
238 lines (200 loc) · 11.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
import pytest
import sqlite3
import os
from unittest.mock import patch, MagicMock
# импортируем все функции из основного файла с программой (sqlite_task)
from sqlite_task import create_connection, initialize_database, execute_query, add_book, get_all_books, update_book, delete_book
@pytest.fixture
def in_memory_db():
"""
Создает и инициализирует временное подключение к базе данных SQLite,
существующей исключительно в оперативной памяти (':memory:').
Эта фикстура обеспечивает:
- Изоляцию тестов:
Для каждого теста, который ее использует, создается абсолютно новая и чистая база данных,
предотвращающая побочные эффекты между тестами.
- Управление жизненным циклом:
Автоматически создает подключение перед тестом и корректно закрывает его после завершения теста.
- Готовность к использованию:
Возвращает инициализированный объект sqlite3.Connection, готовый для выполнения запросов.
:return: sqlite3.Connection: Объект подключения к базе данных в памяти.
"""
db_path = ':memory:'
conn = create_connection(db_path)
if conn is None:
pytest.fail('Не удалось создать подключение к базе данных в памяти для осуществления тестов.')
if not initialize_database(db_path, conn=conn):
pytest.fail('Не удалось инициализировать базу данных в памяти.')
yield conn
conn.close()
# Тесты для add_book
@pytest.mark.parametrize(
'title, author, year',
[
('Book Alpha', 'Author A', 2000),
('Book Beta', 'Author B', None)
]
)
def test_add_book_parametrized_successfully(
in_memory_db: sqlite3.Connection,
title: str,
author: str,
year: int | None):
"""
Тестирует успешное добавление книги с валидными значениями, включая None для года издания.
:param in_memory_db: sqlite3.Connection: Объект подключения к базе данных в памяти.
:param title: str: Название книги.
:param author: str: Автор книги.
:param year: int | None: Год издания книги (или None, если не указано).
"""
book_id = add_book(':memory:', title, author, year, conn=in_memory_db)
assert book_id is not None
assert isinstance(book_id, int)
# Проверяем, что книга действительно добавлена
cursor = execute_query(in_memory_db, 'SELECT title, author, year FROM books WHERE id = ?', (book_id,))
assert cursor is not None
row = [dict(row) for row in cursor]
assert len(row) == 1
assert row[0] == {'title': title, 'author': author, 'year': year}
@pytest.mark.parametrize(
'title, author, year',
[
(None, 'Author X', 2020),
('Book Y', None, 2000)
]
)
def test_add_book_parametrizes_failure_cases(
in_memory_db: sqlite3.Connection,
title: str | None,
author: str | None,
year: int | None):
"""
Тестирует неудачное добавление книги с неверными параметрами (title/author - NOT NULL).
Ожидается, что функция add_book вернет None при ошибке.
:param in_memory_db: sqlite3.Connection: Объект подключения к базе данных в памяти.
:param title: str | None: Название книги (или None, если не указано).
:param author: str | None: Автор книги (или None, если не указано).
:param year: int | None: Год издания книги (или None, если не указано).
"""
book_id = add_book(':memory:', title, author, year, conn=in_memory_db)
assert book_id is None
# Тесты для get_all_books
def test_get_all_books_empty(in_memory_db: sqlite3.Connection):
"""
Тестирует, что функция get_all_books возвращает пустой список, если в базе данных нет книг.
:param in_memory_db: sqlite3.Connection: Объект подключения к базе данных в памяти.
"""
books = get_all_books(':memory:', conn=in_memory_db)
assert books is not None
assert len(books) == 0
def test_get_all_books_multiple(in_memory_db: sqlite3.Connection):
"""
Тестирует, что функция get_all_books корректно возвращает все имеющиеся книги в базе данных.
:param in_memory_db: sqlite3.Connection: Объект подключения к базе данных в памяти.
"""
add_book(':memory:', 'Test title X', 'Test author X', 2015, conn=in_memory_db)
add_book(':memory:', 'Test title Y', 'Test author Y', 1987, conn=in_memory_db)
books = get_all_books(':memory:', conn=in_memory_db)
assert books is not None
assert len(books) == 2
assert books[0]['title'] == 'Test title X'
assert books[1]['author'] == 'Test author Y'
# Тесты для delete_book
def test_delete_book_successfully(in_memory_db: sqlite3.Connection):
"""
Тестирует, что функция delete_book успешно удаляет книгу по-указанному ID.
Ожидается, что функция delete_book вернет True.
:param in_memory_db: sqlite3.Connection: Объект подключения к базе данных в памяти.
"""
# Добавляем книгу, чтобы было что удалять, year может быть None
book_id = add_book(':memory:', 'Test book for delete', 'Test author 2', conn=in_memory_db)
assert book_id is not None
result = delete_book(':memory:', book_id, conn=in_memory_db)
assert result is True
# Проверяем, что книга удалена
cursor = execute_query(in_memory_db, 'SELECT COUNT(*) FROM books WHERE id = ?', (book_id,))
count = list(map(tuple, cursor))[0][0]
assert count == 0
def test_delete_non_existent_book(in_memory_db: sqlite3.Connection):
"""
Тестирует попытку удаления книги, которой нет в базе данных.
Ожидается, что функция delete_book вернет False.
:param in_memory_db: sqlite3.Connection: Объект подключения к базе данных в памяти.
"""
result = delete_book(':memory:', 999, conn=in_memory_db)
assert result is False
@patch('sqlite_task.create_connection', return_value=None)
def test_delete_book_no_connection(mock_create_connection: MagicMock):
"""
Тестирует поведение функции delete_book при невозможности установить соединение с базой данных.
Имитирует сбой функции create_connection, которая возвращает None.
Ожидается, что delete_book корректно обработает эту ситуацию и вернет False,
а create_connection будет вызвана ровно один раз.
:param mock_create_connection: mock-объект.
"""
result = delete_book(':memory:', 1)
assert result is False
mock_create_connection.assert_called_once_with(':memory:')
# Тесты для update_book
@pytest.mark.parametrize(
'new_title, new_author, new_year',
[
('New title', 'New author', 2024),
(None, 'Author X', 2020),
('Title N', None, 1989),
('Title Y', 'Author Y', None),
(None, None, 2015),
(None, None, None)
]
)
def test_update_parametrized_successfully(
in_memory_db: sqlite3.Connection,
new_title: str | None,
new_author: str | None,
new_year: int | None):
"""
Тестирует успешное обновление информации о книге и отсутствие изменений,
в случае непереданных новых данных (Все поля None).
:param in_memory_db: sqlite3.Connection: Объект подключения к базе данных в памяти.
:param new_title: str | None: Новое название книги (или None, если не меняем).
:param new_author: str | None: Новый автор книги (или None, если не меняем).
:param new_year: int | None: Новый год издания книги (или None, если не меняем).
"""
initial_title = 'Old title'
initial_author = 'Old author'
initial_year = 2000
book_id = add_book(':memory:', initial_title, initial_author, initial_year, conn=in_memory_db)
assert book_id is not None
updated = update_book(':memory:', book_id, new_title, new_author, new_year, conn=in_memory_db)
books = get_all_books(':memory:', conn=in_memory_db)
assert len(books) == 1
# Определяем ожидаемые значения после обновления
expected_title = new_title if new_title is not None else initial_title
expected_author = new_author if new_author is not None else initial_author
expected_year = new_year if new_year is not None else initial_year
# Проверяем, что обновились или остались прежними указанные поля
assert books[0]['title'] == expected_title
assert books[0]['author'] == expected_author
assert books[0]['year'] == expected_year
# Убедимся, что ID книги не изменился
assert books[0]['id'] == book_id
def test_update_non_existent_book(in_memory_db: sqlite3.Connection):
"""
Тестирует попытку обновить информацию о книге, которой нет в базе данных.
Ожидается, что функция update_book вернет False
:param in_memory_db: sqlite3.Connection: Объект подключения к базе данных в памяти.
"""
updated = update_book(':memory:', 999, 'Any title', 'Any author', 2020, conn=in_memory_db)
assert updated is False
@patch('sqlite_task.create_connection', return_value=None)
def test_update_book_no_connection(mock_create_connection: MagicMock):
"""
Тестирует поведение функции update_book при невозможности установить соединение с базой данных.
Имитирует сбой функции create_connection, которая возвращает None.
Ожидается, что update_book корректно обработает эту ситуацию и вернет False,
а create_connection будет вызвана ровно один раз.
:param mock_create_connection: mock-объект.
"""
result = update_book(':memory:', 1, 'Title', 'Author', 2000)
assert result is False
mock_create_connection.assert_called_once_with(':memory:')