如何在单元测试中Mock cx_Oracle的cursor.execute()以返回0行?
解决cx_Oracle单元测试Mock cursor.execute()的问题
错误原因
你遇到的TypeError: Need a valid target to patch. You supplied: 'cx_Oracle',是因为mock.patch的目标路径错误。直接patch顶层的cx_Oracle模块无效,必须patch你的业务代码模块中导入的cx_Oracle实例。假设你的业务代码文件名为dump_intexdb_n_load.py,正确的patch目标应该是dump_intexdb_n_load.cx_Oracle。
另外测试代码还存在两个问题:
- 业务代码没有用上下文管理器(
with语句)处理cursor,所以不需要设置__enter__返回值 - 模拟
cursor.execute.return_value = []无效,因为遍历cursor是靠它的迭代器,不是execute的返回值
修正后的测试代码
@mock.patch('dump_intexdb_n_load.cx_Oracle') # 替换为你的业务代码模块名.cx_Oracle def test_invalid_data(self, mock_cx_Oracle): print("Starting test : Test with data file having size < 100000") mock_cursor = mock.MagicMock() # 模拟execute执行成功(execute本身不返回查询结果,无需设置返回值为列表) mock_cursor.execute.return_value = None # 模拟cursor迭代返回空,即没有数据行 mock_cursor.__iter__.return_value = iter([]) # 模拟cursor.description,保证表头获取逻辑不报错,可根据实际查询字段调整 mock_cursor.description = [('COLUMN1',), ('COLUMN2',)] # 关联连接与cursor:connect返回的connection调用cursor()得到mock_cursor mock_cx_Oracle.connect.return_value.cursor.return_value = mock_cursor with self.assertRaises(SystemExit) as cm: dump_intexdb_n_load.main() self.assertEqual(cm.exception.code, 1)
关键修改点说明
- 修正patch路径:把
@mock.patch('cx_Oracle')改成@mock.patch('你的业务模块名.cx_Oracle'),确保mock的是业务代码里实际使用的cx_Oracle对象。 - 正确模拟cursor迭代:业务代码通过
for row in cursor:遍历结果,所以需要让mock_cursor.__iter__.return_value返回空迭代器,模拟0行数据的情况。 - 处理cursor.description:如果业务代码需要获取表头,即使无数据行,cursor.description也需有字段信息(否则会抛出迭代None的错误),所以要设置模拟的字段列表。
- 移除不必要的__enter__设置:业务代码未使用
with connection.cursor() as cursor:写法,无需设置__enter__返回值,直接让connection.cursor()返回mock_cursor即可。
内容的提问来源于stack exchange,提问作者Amruta
相关产品推荐
相关产品推荐

