You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Pytest中Mock直接导入的read_sql函数(无需重构代码)

问题描述

我正在用Pytest为Python项目编写单元测试,需要Mock外部仓库模块sql_services中的read_sql函数。目前只能通过import sql_services后调用sql_services.read_sql的方式Mock该函数,但无法Mock通过from sql_services import read_sql直接导入的函数,而我的代码库正采用这种直接导入的方式。

待测试的entry.py代码:

from sql_services import read_sql

def foo():
    df = read_sql("SELECT * FROM schema.table")
    return df

我的单元测试文件代码:

import pytest
import unittest.mock as mock
import pandas as pd

import sql_services

from entry import foo

@mock.patch("sql_services.read_sql")
def test_read_sql(mock_read_sql):
    mock_read_sql.return_value = pd.DataFrame()
    df = sql_services.read_sql("SELECT * FROM schema.table")
    assert df.empty

@mock.patch("sql_services.read_sql")
def test_do_a_read(mock_read_sql):
    mock_read_sql.return_value = pd.DataFrame()
    df = foo()

    assert df.empty

第一个测试通过,但第二个测试失败,因为foo实际从数据库读取了数据。请问是否有无需重构整个代码库即可Mockfoo中该函数的方法?

解决方案

问题核心是Mock路径不正确:当使用from sql_services import read_sql时,entry模块会生成一个本地的read_sql引用,指向原模块的函数。此时Mock原模块sql_services.read_sql,并不会改变entry模块里已经导入的那个本地引用。

无需重构代码的解决方法是:Mockentry模块中本地的read_sql引用,也就是把测试中的@mock.patch("sql_services.read_sql")替换为@mock.patch("entry.read_sql")。

修改后的测试代码:

import pytest
import unittest.mock as mock
import pandas as pd

from entry import foo

@mock.patch("entry.read_sql")
def test_do_a_read(mock_read_sql):
    mock_read_sql.return_value = pd.DataFrame()
    df = foo()

    assert df.empty

这样修改后,测试会替换entry模块中read_sql的本地引用,foo调用的就是Mock后的函数,不会再访问真实数据库。

内容的提问来源于stack exchange,提问作者Jacob Gladman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 05:23:19