如何用pytest为含SQLAlchemy数据库调用的函数替换假数据做单元测试
要解决这个问题,我们可以通过mock(模拟)db_fetch函数来完全绕过真实的数据库操作,这样测试就不用依赖数据库fixture,速度会大幅提升,同时还能让测试更独立(不会因为数据库数据变化导致测试失败)。下面给你两种常用的实现方式,都是pytest生态里的标准做法:
方法1:使用pytest的monkeypatch fixture
monkeypatch是pytest自带的fixture,专门用来临时替换模块、类或对象的属性,非常适合这种场景。
假设你的业务代码在my_module.py里:
# my_module.py def db_fetch(par1): # 真实的SQLAlchemy查询逻辑 pass def foo(par1): db_value = db_fetch(par1) if db_value > 10: return db_value * 5 else: return 1
对应的测试文件test_my_module.py可以这么写:
# test_my_module.py from my_module import foo def test_foo_when_db_value_greater_than_10(monkeypatch): # 定义一个模拟的db_fetch函数,返回我们预设的假数据 def mock_db_fetch(par1): # 这里可以根据传入的par1返回不同的值,模拟不同场景 return 15 # 替换my_module里的db_fetch为我们的模拟函数 monkeypatch.setattr("my_module.db_fetch", mock_db_fetch) # 调用foo并验证结果 assert foo("test_param") == 75 # 15*5=75 def test_foo_when_db_value_less_than_or_equal_10(monkeypatch): def mock_db_fetch(par1): return 8 monkeypatch.setattr("my_module.db_fetch", mock_db_fetch) assert foo("test_param") == 1
方法2:使用标准库的unittest.mock.patch
Python标准库的unittest.mock.patch功能更丰富,除了替换函数返回值,还能验证函数的调用次数、传入参数等,适合需要更细致测试的场景。
同样针对上面的业务代码,测试可以这么写:
# test_my_module.py from unittest.mock import patch from my_module import foo @patch("my_module.db_fetch") # 装饰器指定要替换的目标函数 def test_foo_when_db_value_greater_than_10(mock_db_fetch): # 设置模拟函数的返回值 mock_db_fetch.return_value = 15 # 调用foo result = foo("test_param") # 验证结果 assert result == 75 # 额外验证:db_fetch是否被正确调用了一次,且参数是"test_param" mock_db_fetch.assert_called_once_with("test_param") @patch("my_module.db_fetch") def test_foo_when_db_value_less_than_or_equal_10(mock_db_fetch): mock_db_fetch.return_value = 8 result = foo("test_param") assert result == 1 mock_db_fetch.assert_called_once_with("test_param")
关键注意点
- 替换路径要正确:不管用哪种方法,替换的都是
foo所在模块里的db_fetch引用(也就是my_module.db_fetch),而不是db_fetch定义的原模块。这是mock的核心原则——替换被测试代码实际使用的对象。 - 灵活设置返回值:如果需要根据不同的
par1返回不同假数据,可以在模拟函数里加逻辑,或者用side_effect(比如mock_db_fetch.side_effect = lambda x: 20 if x == "special" else 5)。
这样修改后,你的测试完全脱离了真实数据库,运行速度会快很多,而且测试用例的结果完全由你预设的假数据控制,稳定性也更高。
内容的提问来源于stack exchange,提问作者Gathua
相关产品推荐
相关产品推荐

