2022-12-22

Mocking Azure BlobServiceClient in Python

I am trying to write a unit test that will test azure.storage.blob.BlobServiceClient class and its methods. Below is my code

A fixture in the conftest.py

@pytest.fixture
def mock_BlobServiceClient(mocker):

    azure_ContainerClient = mocker.patch("azure.storage.blob.ContainerClient", mocker.MagicMock())

    azure_BlobServiceClient= mocker.patch("azure_module.BlobServiceClient", mocker.MagicMock())
    azure_BlobServiceClient.from_connection_string.return_value
    azure_BlobServiceClient.get_container_client.return_value = azure_ContainerClient
    azure_ContainerClient.list_blob_names.return_value = "test"
    azure_ContainerClient.get_container_client.list_blobs.return_value = ["test"]

    yield azure_BlobServiceClient

Contents of the test file

from azure_module import AzureBlob


def test_AzureBlob(mock_BlobServiceClient):
    azure_blob = AzureBlob()

    # This assertion passes
    mock_BlobServiceClient.from_connection_string.assert_called_once_with("testconnectionstring")

    # This assertion fails
    mock_BlobServiceClient.get_container_client.assert_called()

Contents of the azure_module.py

from azure.storage.blob import BlobServiceClient
import os


class AzureBlob:

    def __init__(self) -> None:
        """Initialize the azure blob"""
        self.azure_blob_obj = BlobServiceClient.from_connection_string(os.environ["AZURE_STORAGE_CONNECTION_STRING"])
        self.azure_container = self.azure_blob_obj.get_container_client(os.environ["AZURE_CONTAINER_NAME"])

My test fails when I execute it with below error message

>       mock_BlobServiceClient.get_container_client.assert_called()
E       AssertionError: Expected 'get_container_client' to have been called.

I am not sure why it says that the get_container_client wasn't called when it was called during the AzureBlob's initialization.

Any help is very much appreciated.

Update 1

I believe this is a bug in the unittest's MagicMock itself. Per Michael Delgado suggested that I dialed the code to a bare minimum to test and identify the issue, and I concluded that the MagicMock was causing the problem. Below are my findings:

conftest.py

@pytest.fixture
def mock_Blob(mocker):
    yield mocker.patch("module.BlobServiceClient")

test_azureblob.py

def test_AzureBlob(mock_Blob):

    azure_blob = AzureBlob()
    print(mock_Blob)
    print(mock_Blob.mock_calls)
    print(mock_Blob.from_connection_string.mock_calls)
    print(mock_Blob.from_connection_string.get_container_client.mock_calls)
    assert False  # <- Intentional fail

After running the test, I got the following results.

$ pytest -vv
.
.
.
------------------------------------------------------------------------------------------- Captured stdout call -------------------------------------------------------------------------------------------
<MagicMock name='BlobServiceClient' id='140704187870944'>
[call.from_connection_string('AZURE_STORAGE_CONNECTION_STRING'),
 call.from_connection_string().get_container_client('AZURE_CONTAINER_NAME')]
[call('AZURE_STORAGE_CONNECTION_STRING'),
 call().get_container_client('AZURE_CONTAINER_NAME')]
[]
.
.
.

The prints clearly show that the get_container_client was seen being called, but the mocked method did not register it at its level. That led me to conclude that the MagicMock has a bug which I will report to the developers for further investigation.



No comments:

Post a Comment