使用pytest-mock如何mock SQLAlchemy对象的insert、execute等方法
解决方案
场景1:单独单元测试some_function2(推荐,测试隔离度最高)
因为some_function2的db_tools是入参,不需要做任何patch,直接构造符合要求的Mock对象传入即可:
def test_some_function2(mocker): # 1. 构造模拟的sql_query对象 mock_sql_query = mocker.Mock() # 2. 构造模拟的table对象:insert()返回的对象要有values方法,values返回mock_sql_query mock_table = mocker.Mock() mock_table.insert.return_value.values.return_value = mock_sql_query # 3. 构造模拟的engine对象:有execute方法 mock_engine = mocker.Mock() # 4. 组装db_tools入参 test_db_tools = { "table": mock_table, "engine": mock_engine } # 测试用的data test_data = {"col1": "val1", "col2": "val2"} # 调用待测函数 some_function2(test_db_tools, test_data) # 可选:验证调用逻辑是否符合预期 # 验证insert方法被调用 mock_table.insert.assert_called_once() # 验证values方法传入了正确的测试数据 mock_table.insert.return_value.values.assert_called_once_with(test_data) # 验证execute方法传入了正确的sql查询对象 mock_engine.execute.assert_called_once_with(mock_sql_query)
这种方式完全不需要依赖some_function1的逻辑,也不需要连接数据库,纯粹验证some_function2本身的逻辑正确性。
场景2:联动测试some_function1 + some_function2
如果你需要测试两个函数的联动流程,就需要调整之前对create_engine和Table的patch,让它们返回的Mock对象带对应的方法:
def test_full_flow(mocker): # 构造带execute方法的mock engine mock_engine = mocker.Mock() mocker.patch('my_module.create_engine', return_value=mock_engine) # MetaData原来的返回值可以保留,或者也换成Mock,不影响后续逻辑 mocker.patch('my_module.MetaData', return_value=mocker.Mock()) # 构造带insert方法的mock table mock_table = mocker.Mock() mock_sql_query = mocker.Mock() mock_table.insert.return_value.values.return_value = mock_sql_query mocker.patch('my_module.Table', return_value=mock_table) # 调用第一个函数生成db_tools db_tools = some_function1() # 调用第二个函数 test_data = {"col1": "val1"} some_function2(db_tools, test_data) # 同样可以做各种调用断言 mock_engine.execute.assert_called_once_with(mock_sql_query)
内容的提问来源于stack exchange,提问作者eduardokapp
相关产品推荐
相关产品推荐

