You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Mocking问题:无法获取Mock对象的返回值

问题:Mock Azure Blob存储调用返回MagicMock而非预期字符串?

在使用pytest和unittest.mock为GetDataStep类编写单元测试时,尝试Mock Azure Blob存储服务调用以返回指定字符串,但断言失败,返回的是MagicMock对象而非预期值,错误信息如下:

AssertionError: assert == '1,2,3\n4,5,6'

待测试类代码

class GetDataStep:
    blob_service_client_instance = BlobServiceClient

    def execute(self, params: dict) -> str:
        logging.info(f"Executing Step: {self.__class__.__name__}")
        file_name = params["file_name"]
        storage_account_url = params["storage_account_url"]
        storage_account_key = params["storage_account_key"]
        container_name = params["container_name"]

        logging.info(f"Downloading {file_name}.")
        blob_service_client_instance = self.blob_service_client_instance(
            account_url=storage_account_url, credential=storage_account_key
        )

        blob_client_instance = blob_service_client_instance.get_blob_client(
            container_name, file_name, snapshot=None
        )

        try:
            blob_data = blob_client_instance.download_blob()
            data = blob_data.readall()
        except ResourceNotFoundError as rnfe:
            logging.info(f"Error: {file_name} does not exist!")
            logging.exception(rnfe)
            raise rnfe

        logging.info("File downloaded successfully")

        logging.info(f"Finished Step: {self.__class__.__name__}")
        return data.decode("utf-8")

测试代码(原错误版本)

@patch("azure.storage.blob.BlobServiceClient")
def test_execute(mock_blob_service_client):
    
    get_data_step = steps.GetDataStep()

    # Define the input parameters
    params = {
        "file_name": "test_file.csv",
        "storage_account_url": "https://testaccount.blob.core.windows.net",
        "storage_account_key": "test_key",
        "container_name": "test_container",
    }

    # Define a mock blob client that will return the expected file data
    mock_blob_client = mock_blob_service_client.return_value.get_blob_client.return_value
    mock_blob_client.download_blob.readall.decode.return_value = "1,2,3\n4,5,6"

    get_data_step.blob_service_client_instance = mock_blob_service_client

    # Execute the step
    file_data = get_data_step.execute(params)

    # Verify that the BlobServiceClient was instantiated with the correct arguments
    mock_blob_service_client.assert_called_once_with(
        account_url="https://testaccount.blob.core.windows.net",
        credential="test_key"
    )

    
    mock_blob_service_client.return_value.get_blob_client.assert_called_once_with(
        params['container_name'], params['file_name'], snapshot=None
    )
    print(file_data)
    
    assert file_data == "1,2,3\n4,5,6"

原因分析

问题出在Mock的层级设置错误:

  • 原测试中直接给mock_blob_client.download_blob.readall.decode.return_value赋值,但download_blob()、readall()都是需要调用的方法,而非属性。
  • 原代码逻辑是:调用download_blob()得到blob对象 → 调用该对象的readall()得到二进制数据 → 调用decode()得到字符串。错误的Mock方式没有正确模拟这一系列方法调用的返回值,导致最终返回未正确配置的MagicMock对象。

解决方法

正确模拟每一层方法调用的返回值:

  1. 先获取download_blob()方法的返回值Mock对象
  2. 给readall()设置返回二进制格式的预期数据(原代码中readall()返回的是bytes类型,后续会自动decode为字符串)

修改后的测试代码如下:

@patch("azure.storage.blob.BlobServiceClient")
def test_execute(mock_blob_service_client):
    
    get_data_step = steps.GetDataStep()

    params = {
        "file_name": "test_file.csv",
        "storage_account_url": "https://testaccount.blob.core.windows.net",
        "storage_account_key": "test_key",
        "container_name": "test_container",
    }

    # 正确设置Mock层级
    mock_blob_client = mock_blob_service_client.return_value.get_blob_client.return_value
    # 模拟download_blob()方法返回的对象
    mock_download_blob = mock_blob_client.download_blob.return_value
    # 给readall()设置二进制返回值,原代码会自动decode成字符串
    mock_download_blob.readall.return_value = b"1,2,3\n4,5,6"

    get_data_step.blob_service_client_instance = mock_blob_service_client

    file_data = get_data_step.execute(params)

    mock_blob_service_client.assert_called_once_with(
        account_url="https://testaccount.blob.core.windows.net",
        credential="test_key"
    )

    mock_blob_service_client.return_value.get_blob_client.assert_called_once_with(
        params['container_name'], params['file_name'], snapshot=None
    )
    
    assert file_data == "1,2,3\n4,5,6"

内容的提问来源于stack exchange,提问作者Ropali Munshi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 04:55:14