Ошибка AssertionError: expected call not found при запуске тестов библиотеки python unittest
Написал тест для функции с вложенными функциями. Но при запуске тестов появляется ошибка.
Тестируемые функции:
Файл google_drive.uploader.py
def load_file_to_disk(file_path: str, name: str, folder_id: str) -> None:
"""Подключается к Google Drive и загружает файл на диск, используя путь к
файлу, название и id папки(куда нужно загрузить файл), взятые из
аргументов."""
max_retries = 3
attempt = 0
success = False
while attempt < max_retries and not success:
try:
if check_file_exist(name, folder_id):
try:
file_id = get_id_object_by_name(name, folder_id)
result = update_file(file_path, file_id)
if result['id']:
success = True
logger.debug(f"Файл {name} обновлен в папке "
f"'{folder_id}'.")
except Exception as e:
logger.error(f'Ошибка при обновлении файла {name}: {e}')
else:
result = create_file(name, folder_id, file_path)
if result['id']:
success = True
logger.debug(f"Файл {name} загружен в папку "
f"'{folder_id}'.")
except Exception as e:
attempt += 1
logger.error(f"Ошибка загрузки/обновления файла на Google Drive. "
f"Попыток: {attempt}. Ошибка: {e}")
if attempt < max_retries:
time.sleep(2)
if not success:
send_mail(f"Ошибка загрузки файла {name} в папку с id '{folder_id}' "
f"после {max_retries} attempts.")
logger.error(f"Ошибка загрузки файла {name} в папку с id "
f"'{folder_id}'.")
def check_file_exist(name: str, parent_folder_id: str) -> bool:
"""Получает все файлы с гугл диска, которые удовлетворяют условия запроса:
файлы из папки с id 'parent_folder_id' и с именами 'main_log.log или
'widget_log_bd'."""
service = auth_gdrive()
query = (f"'{parent_folder_id}' in parents and name = '{name}'")
results = service.files().list(
pageSize=10,
fields="nextPageToken, files(id, name, mimeType)",
q=query).execute()
logger.debug(f"Выполнена проверка на существование файла "
f"'{name}' в папке с id "
f"'{parent_folder_id}'.")
if not results["files"]:
logger.debug(f"Файл '{name}' отсутствуtт.")
return False
logger.debug(f"Файл '{name}' найден.")
return True
def get_id_object_by_name(name: str, folder_id: str = None) -> str:
"""Подключается к Google Drive и получает id папки или файла, по названию,
переданному в аргументе и возвращает его в виде {название: id}."""
service = auth_gdrive()
if folder_id:
query = f"name = '{name}' and '{folder_id}' in parents"
else:
query = f"name = '{name}'"
r = service.files().list(pageSize=10,
fields="nextPageToken, files(id, name, mimeType)",
q=query).execute()
if r["files"]:
logger.debug(f"Получен id файла {name} в папке с id '{folder_id}'.")
return r["files"][0]["id"]
else:
logger.debug(f"id файла {name} в папке {folder_id} не найден. "
f"Проверьте наличие файла в папке с id {folder_id} '.")
def update_file(file_path: str, file_id: str) -> Dict[str, str]:
"""Обновляет файл на гугл-диске с помощью пути и id файла."""
service = auth_gdrive()
media = MediaFileUpload(file_path, resumable=True)
return service.files().update(
fileId=file_id,
media_body=media).execute()
def create_file(name: str, folder_id: str, file_path: str) -> Dict[str, str]:
"""Загружает файл на Google Drive, используя имя, id родительской папки, в
которой нужно создать, и путь к файлу."""
service = auth_gdrive()
file_metadata = {
"name": name,
"parents": [folder_id]
}
media = MediaFileUpload(file_path, resumable=True)
return service.files().create(
body=file_metadata,
media_body=media,
fields="id,name"
).execute()
Файл tests.py
@patch('google_drive.uploader.check_file_exist')
@patch('google_drive.uploader.get_id_object_by_name')
@patch('google_drive.uploader.update_file')
@patch('google_drive.uploader.create_file')
def test_load_file_to_disk(self, mock_check_file, mock_get_id,
mock_update_file, mock_create_file):
mock_response_check = MagicMock()
response_dict_check = True
mock_response_check.json.return_value = response_dict_check
mock_check_file.return_value = mock_response_check
mock_response_get = MagicMock()
response_dict_get = '18Wwvuye8dOjCZfJzGf45yQvB87Lazbzu'
mock_response_get.json.return_value = response_dict_get
mock_get_id.return_value = mock_response_check
mock_response_update = MagicMock()
response_dict_update = {'kind': 'drive#file',
'id': '18Wwvuye8dOjCZfJzGf45yQvB87Lazbzu',
'name': 'main_log_i-analytic6.pz.cp.log',
'mimeType': 'text/plain'
}
mock_response_update.json.return_value = response_dict_update
mock_update_file.return_value = mock_response_check
mock_response_create = MagicMock()
response_dict_create = {'id': '18Wwvuye8dOjCZfJzGf45yQvB87Lazbzu'}
mock_response_create.json.return_value = response_dict_create
mock_create_file.return_value = mock_response_check
result = load_file_to_disk('file_path', 'name', 'folder_id')
print(mock_check_file.call_args_list) # Отладочный вывод
print(mock_get_id.call_args_list)
print(mock_update_file.call_args_list)
print(mock_create_file.call_args_list)
mock_check_file.assert_called_with('name', 'parent_folder_id')
mock_get_id.assert_called_with('name', 'folder_id')
mock_update_file.assert_called_with('file_path', 'file_id')
mock_create_file.assert_not_called()
self.assertEqual(result, None)
if __name__ == "__main__":
unittest.main()
Ошибка:
python -m unittest
DEBUG:google_drive.uploader:Запуск автозагрузчика...
DEBUG:google_drive.uploader:Получен id файла main_log_i-analytic6.pz.cp.log в папке с id '1DvWKXFKjddttDIWrqyKo6DqTgpv6rfFH'.
17OaoGOZkIUhRP658nXMHYshSDg6KByzX
{'kind': 'drive#file', 'id': '17OaoGOZkIUhRP658nXMHYshSDg6KByzX', 'name': 'main_log_i-analytic6.pz.cp.log', 'mimeType': 'text/plain'}
INFO:google_drive.uploader:Создана папка 20_12_2024.
.DEBUG:google_drive.uploader:Получен id файла exist_file в папке с id 'test_folder'.
.DEBUG:google_drive.uploader:id файла nonexistent-file в папке test_folder не найден. Проверьте наличие файла в папке с id test_folder '.
.DEBUG:google_drive.uploader:Файл name обновлен в папке 'folder_id'.
[]
[call('file_path', <MagicMock name='create_file()' id='2765363568928'>)]
[call('name', 'folder_id')]
[call('name', 'folder_id')]
F
======================================================================
FAIL: test_load_file_to_disk (tests.TestUploader.test_load_file_to_disk)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\DOrlov\AppData\Local\Programs\Python\Python313\Lib\unittest\mock.py", line 1424, in patched
return func(*newargs, **newkeywargs)
File "C:\Users\DOrlov\Рабочая папка\Projects\admin-tools\tests.py", line 102, in test_load_file_to_disk
mock_check_file.assert_called_with('name', 'parent_folder_id')
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\DOrlov\AppData\Local\Programs\Python\Python313\Lib\unittest\mock.py", line 968, in assert_called_with
raise AssertionError(error_message)
AssertionError: expected call not found.
Expected: create_file('name', 'parent_folder_id')
Actual: not called.
----------------------------------------------------------------------
Ran 4 tests in 0.020s
FAILED (failures=1)
Предполагаю, что ошибка связана с
mock_check_file.assert_called_with('name', 'parent_folder_id')
mock_get_id.assert_called_with('name', 'folder_id')
mock_update_file.assert_called_with('file_path', 'file_id')
mock_create_file.assert_not_called()
Так как, закомментировав этот участок кода, тесты проходят, но по принтам можно сказать, что есть какие-то проблемы:
$ python -m unittest tests.TestUploader.test_load_file_to_disk
DEBUG:google_drive.uploader:Запуск автозагрузчика...
DEBUG:google_drive.uploader:Файл name обновлен в папке 'folder_id'.
[]
[call('file_path', <MagicMock name='create_file()' id='2799013179952'>)]
[call('name', 'folder_id')]
[call('name', 'folder_id')]
F
======================================================================
FAIL: test_load_file_to_disk (tests.TestUploader.test_load_file_to_disk)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\DOrlov\AppData\Local\Programs\Python\Python313\Lib\unittest\mock.py", line 1424, in patched
return func(*newargs, **newkeywargs)
File "C:\Users\DOrlov\Рабочая папка\Projects\admin-tools\tests.py", line 102, in test_load_file_to_disk
mock_check_file.assert_called_with(name='name', parent_folder='parent_folder_id')
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\DOrlov\AppData\Local\Programs\Python\Python313\Lib\unittest\mock.py", line 968, in assert_called_with
raise AssertionError(error_message)
AssertionError: expected call not found.
Expected: create_file(name='name', parent_folder='parent_folder_id')
Actual: not called.
----------------------------------------------------------------------
Ran 1 test in 0.005s
FAILED (failures=1)
Ответы (1 шт):
У вас в тесте противоречие. Вы одновременно желаете и не желаете, чтобы функция create_file
была вызвана:
mock_check_file.assert_called_with('name', 'parent_folder_id')
...
mock_create_file.assert_not_called()
Какой-то из этих ассертов обязательно сломается.
Судя по логике заглушек, правильным является последняя проверка - метод create_file
не должен вызываться. Смотрите, как вы настраиваете заглушку для check_file_exist
:
mock_response_check = MagicMock()
response_dict_check = True
mock_response_check.json.return_value = response_dict_check
Эта функция должна в тесте всегда возвращать True
. Следовательно тестируемая функция должна всегда заходить в ветку if
с update_file
. В этой ветке нет create_file
, и ассерт mock_check_file.assert_called_with
должен нарушаться.
Если вам нужен тест, в котором create_file
вызывается, то замените response_dict_check = True
на ... = False
и поменяйте ассерты:
mock_get_id.assert_called_with('name', 'folder_id')
mock_update_file.assert_not_called()
mock_check_file.assert_called_with('name', 'parent_folder_id')