对象内部的模拟模块调用

时间:2019-01-04 19:18:30

标签: python mocking python-unittest

我有以下代码

@mock.patch('src.sql_connector.SqlWorkflowConnector')
def mock_workflow_connector(mock_connector):
    mock_connector.return_value.get_connection.return_value = MagicMock()
    mock_connector.return_value.get_cursor.return_value = MagicMock()
    return mock_connector

@mock.patch('src.sql_connector.SqlOverlordConnector')
def mock_overlord_connector(mock_connector):
    mock_connector.return_value.get_connection.return_value = MagicMock()
    mock_connector.return_value.get_cursor.return_value = MagicMock()
    return mock_connector

@mock.patch('src.sql_scrapper.SqlScrapper')
def test_retrieve_metadata(mock_sql_scrapper):
    sql_workflow_connector = mock_workflow_connector()
    sql_overlord_connector = mock_overlord_connector()
    scrapper = SqlScrapper(sql_workflow_connector, sql_overlord_connector)
    data = scrapper.retrieve_metadata("test_sample", "test_id", "test_status")
    print(data)

在我的test_retrieve_meta_data函数中,有以下一行

data = scrapper.retrieve_metadata("test_sample", "test_id", "test_status")

这将调用cursor.execute()调用

我得到的返回值是

<MagicMock name='mock.cursor.execute()' id='4471052104'>
{'sample_name': <MagicMock name='mock.cursor.execute().SampleName' id='4471062824'>}

我希望能够修复此返回值,以便我可以对其进行测试

我该如何更改模拟.cursor.execute()。SampleName调用以返回例如“ test_sample”?

2 个答案:

答案 0 :(得分:1)

首先,我怀疑您当前的模拟使用情况存在错误。您正在修补SqlWorkflowConnectorSqlOverlordConnector类,因此return mock_connector将返回 class 的模拟,而sql_workflow_connector / sql_overlord_connector都是模拟上课。您的SqlScrapper是否真的希望在构造函数中使用类?很有可能它们应该是实例:

scrapper = SqlScrapper(sql_workflow_connector(), sql_overlord_connector())

为避免歧义,我通常用_cls / _instance后缀来命名模拟函数,因此我总是可以回忆起返回的模拟替换了什么。例如,

def mock_workflow_connector_cls(mock_connector):
    ...

第二,回答您的实际问题:只需扩展您已有的模拟对象。示例:

@mock.patch('spam.SqlWorkflowConnector')
def mock_workflow_connector(mock_connector):
    mock_connector.return_value.get_connection.return_value = MagicMock()
    mocked_cursor = MagicMock()
    mocked_cursor.execute.return_value.SampleName = 'test_sample'
    mock_connector.return_value.get_cursor.return_value = mocked_cursor
    return mock_connector

答案 1 :(得分:0)

基于霍夫斯林的反应,我能够进行修改并做出正确的调整。上面提供的示例无法正常工作。

解决方法如下

@mock.patch('src.sql_connector.SqlWorkflowConnector')
def mock_workflow_connector(mock_connector):
    mock_connector.return_value.get_connection.return_value = MagicMock()
    mocked_cursor = MagicMock()
    mocked_cursor.execute.return_value.SampleName = 'test_sample_name'
    mocked_cursor.execute.return_value.ClientSampleId = 'test_client_sample_id'
    mocked_cursor.execute.return_value.ClientSubjectId = 'test_client_subject_id'
    mocked_cursor.execute.return_value.ClientName = 'test_client_name'
    mocked_cursor.execute.return_value.ProjectId = 'test_project_id'
    mocked_cursor.execute.return_value.ProjectName= 'test_project_name'
    mocked_cursor.execute.return_value.WorkflowExecutionId = 12345
    mock_connector.return_value.get_cursor.return_value = mocked_cursor
    print(mock_connector.return_value.get_cursor.return_value)
    mock_connector.cursor = mocked_cursor
    return mock_connector

@mock.patch('src.sql_connector.SqlOverlordConnector')
def mock_overlord_connector(mock_connector):
    mock_connector.return_value.get_connection.return_value = MagicMock()
    mock_connector.return_value.get_cursor.return_value = MagicMock()
    return mock_connector

def test_retrieve_metadata(t_row):
    sql_workflow_connector = mock_workflow_connector()
    sql_overlord_connector = mock_overlord_connector()
    scrapper = SqlScrapper(sql_workflow_connector, sql_overlord_connector)
    data = scrapper.retrieve_metadata("test_sample", "test_id", "test_status")
    print(data)
    print(t_row)
    assert data == t_row