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对象。
解决方法
正确模拟每一层方法调用的返回值:
- 先获取
download_blob()方法的返回值Mock对象 - 给
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
相关产品推荐
相关产品推荐

