Python Unittest中Mock cursor.fetchall()报错,如何正确模拟返回值?
问题描述
对main_func执行集成测试时,尝试Mock cursor.fetchall()以返回模拟值,触发错误:
ModuleNotFoundError: No module named 'src.utils.cursor'; 'src.utils' is not a package
项目结构:
--project --src --tests --test_main.py --main.py --utils.py
相关代码:
utils.py
def update_configuration(configuration, mysql_client): query = "SELECT * from some database" cursor = mysql_client.execute_query(query) function_mapping = cursor.fetchall() cursor.close() configuration["mapping"] = {} for (display_name, formula_name) in function_mapping: configuration["formula_mapping"][formula_name] = display_name
main.py
def main_func(configuration): mysql_client = get_mysql_connection() ut.update_configuration(configuration, mysql_client) # ut 指代 utils.py
test_main.py(原test.py)
@mock.patch("src.utils.cursor.fetchall",return_value = [1,2,3,4]) @mock.patch("src.main.get_sql_connection", return_value = mock.Mock()) def test_initiate_calc(self, dummy1): # 对 main_func 执行集成测试
需求:找到正确的Mock方式,让function_mapping = cursor.fetchall()能获取指定返回值。
解决方案
错误核心是你Mock的路径src.utils.cursor不存在——cursor并非src.utils模块的静态对象,而是mysql_client.execute_query()运行时返回的实例对象,无法直接通过模块路径Mock。正确思路是Mock依赖链上的可寻址对象,逐层控制cursor.fetchall()的返回值:
修改后的测试代码
@mock.patch("src.main.get_mysql_connection") def test_initiate_calc(self, mock_mysql_conn): # 1. 创建Mock cursor,指定fetchall返回符合业务逻辑的结构 mock_cursor = mock.Mock() mock_cursor.fetchall.return_value = [("display_name_1", "formula_name_1"), ("display_name_2", "formula_name_2")] # 2. 让mysql客户端的execute_query方法返回这个mock cursor mock_mysql_conn.return_value.execute_query.return_value = mock_cursor # 3. 准备测试用配置 test_config = {"formula_mapping": {}} # 4. 执行被测试函数 main_func(test_config) # 5. 可选:验证逻辑正确性 assert test_config["formula_mapping"] == {"formula_name_1": "display_name_1", "formula_name_2": "display_name_2"} mock_cursor.close.assert_called_once()
关键说明
- 放弃Mock
src.utils.cursor.fetchall,因为cursor是动态生成的实例,mock.patch只能作用于模块、类、实例属性等可通过路径寻址的对象。 - 从上游依赖开始Mock:
main_func依赖get_mysql_connection返回的客户端,客户端的execute_query返回cursor,因此逐层Mock这些对象的行为,最终控制fetchall()的返回值。 - 原测试中的
get_sql_connection应为笔误,需修正为get_mysql_connection,保证与main.py中的调用一致。
内容的提问来源于stack exchange,提问作者Just another object
相关产品推荐
相关产品推荐

