Python unittest.mock google storage - как добиться исключений. Не обнаружено как побочный эффект - PullRequest
1 голос
/ 09 июля 2020

Я прочитал несколько руководств по насмешкам в Python, но я все еще борюсь: - /

Например, у меня есть функция, переносящая вызов в Google хранилище для записи большого двоичного объекта.

Я бы хотел имитировать метод google.storage.Client (). bucket (bucket_name) , чтобы возвращать исключения.NotFound для указанного c несуществующего ведра. Я использую side_effect для установки исключенного исключения

Вы знаете, что я делаю не так?

Ниже показано, что я пробовал (я использую 2 файла: main2. py и main2_test.py ):

# main2.py
import logging
from google.cloud import storage

def _write_content(bucket_name, blob_name, content):
   storage_client = storage.Client()
   bucket = storage_client.bucket(bucket_name)
   blob = bucket.blob(blob_name)

   try:
        blob.upload_from_string(data=content)
        return True
    except Exception:
        logging.error("Failed to upload blob")
        raise

и

# main2_test.py
import pytest
from unittest.mock import patch
from google.api_core import exceptions
import main2


@patch("main2.storage.Client", autospec=True)
def test_write_content(clientMock):
    bucket_name = "not_existent_bucket"
    clientMock().bucket(bucket_name).side_effect = exceptions.NotFound

    with pytest.raises(exceptions.NotFound):
        main2._write_content(bucket_name, "a_blob_name", '{}')

Пример вызова

pytest main2_test.py::test_write_content

Результат

platform linux -- Python 3.7.7, pytest-5.4.3, py-1.9.0, pluggy-0.13.1
rootdir: /home/user/project, inifile: pytest.ini
plugins: requests-mock-1.8.0
collected 1 item                                                                                                                                                                                     

main2_test.py::test_write_content FAILED                                                                                                                                                       [100%]

============================================================================================== FAILURES ==============================================================================================
_________________________________________________________________________________________ test_write_content _________________________________________________________________________________________

clientMock = <MagicMock name='Client' spec='Client' id='139881522497360'>

    @patch("main2.storage.Client", autospec=True)
    def test_write_content(clientMock):
        bucket_name = "my_bucket"
        clientMock().bucket(bucket_name).side_effect = exceptions.NotFound
    
        with pytest.raises(exceptions.NotFound):
>           main2._write_content(bucket_name, "a_blob_name", '{}')
E           Failed: DID NOT RAISE <class 'google.api_core.exceptions.NotFound'>

main2_test.py:14: Failed
=====================================
FAILED main2_test.py::test_write_content - Failed: DID NOT RAISE <class 'google.api_core.exceptions.NotFound'>
=====================================

1 Ответ

2 голосов
/ 10 июля 2020

У вашего теста две проблемы: вы не издеваетесь над методом, который действительно должен вызывать (upload_from_string), и вы устанавливаете исключение class вместо исключения в качестве побочного эффекта.

Следующее будет работать:

@patch("main2.storage.Client", autospec=True)
def test_write_content(clientMock):
    blob_mock = clientMock().bucket.return_value.blob.return_value  # split this up for readability
    blob_mock.upload_from_string.side_effect = exceptions.NotFound('testing')  # the exception is created here

    with pytest.raises(exceptions.NotFound):
        main2._write_content("not_existent", "a_blob_name", '{}')

Обратите внимание, что установка параметра specifici c для вызова bucket не имеет никакого эффекта, так как он вызывается для имитации, и аргумент просто игнорируется - Я заменил его на return_value, чтобы прояснить это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...