有没有办法使用 mock 在 pytest 中模拟完整的代码?
Is there a way to mock a complete bit of code in pytest using mock?
比如每次测试发现
database.db.session.using_bind("reader")
我想删除 using_bind("reader"))
并只使用
database.db.session
使用 mocker
在conftest.py
中尝试过这样使用它
@pytest.fixture(scope='function')
def session(mocker):
mocker.patch('store.database.db.session.using_bind', return_value=_db.db.session)
但到目前为止没有任何效果。
被测代码:
from store import database
results = database.db.session.using_bind("reader").query(database.Order.id).join(database.Shop).filter(database.Shop.deleted == False).all(),
然后我得到
AttributeError: 'scoped_session' object has no attribute 'using_bind' as an error.
让我们从 MRE 开始,其中被测代码使用假数据库:
from unittest.mock import Mock, patch
class Session:
def using_bind(self, bind):
raise NotImplementedError(f"Can't bind {bind}")
def query(self):
return "success!"
database = Mock()
database.db.session = Session()
def code_under_test():
return database.db.session.using_bind("reader").query()
def test():
assert code_under_test() == "success!"
运行 此测试失败:
E NotImplementedError: Can't bind reader
所以我们想在 code_under_test
中模拟 session.using_bind
以便它 returns session
-- 这将使我们的测试通过。
我们使用 patch
来做到这一点,就像这样:
@patch("test.database.db.session.using_bind")
def test(mock_bind):
mock_bind.return_value = database.db.session
assert code_under_test() == "success!"
请注意,我的代码位于一个名为 test.py
的文件中,因此我的 patch
调用适用于 test
模块——您需要调整它以指向该模块在您自己的代码中进行测试。
另请注意,在调用被测代码之前,我需要设置我的模拟。
比如每次测试发现
database.db.session.using_bind("reader")
我想删除 using_bind("reader"))
并只使用
database.db.session
使用 mocker
在conftest.py
@pytest.fixture(scope='function')
def session(mocker):
mocker.patch('store.database.db.session.using_bind', return_value=_db.db.session)
但到目前为止没有任何效果。
被测代码:
from store import database
results = database.db.session.using_bind("reader").query(database.Order.id).join(database.Shop).filter(database.Shop.deleted == False).all(),
然后我得到
AttributeError: 'scoped_session' object has no attribute 'using_bind' as an error.
让我们从 MRE 开始,其中被测代码使用假数据库:
from unittest.mock import Mock, patch
class Session:
def using_bind(self, bind):
raise NotImplementedError(f"Can't bind {bind}")
def query(self):
return "success!"
database = Mock()
database.db.session = Session()
def code_under_test():
return database.db.session.using_bind("reader").query()
def test():
assert code_under_test() == "success!"
运行 此测试失败:
E NotImplementedError: Can't bind reader
所以我们想在 code_under_test
中模拟 session.using_bind
以便它 returns session
-- 这将使我们的测试通过。
我们使用 patch
来做到这一点,就像这样:
@patch("test.database.db.session.using_bind")
def test(mock_bind):
mock_bind.return_value = database.db.session
assert code_under_test() == "success!"
请注意,我的代码位于一个名为 test.py
的文件中,因此我的 patch
调用适用于 test
模块——您需要调整它以指向该模块在您自己的代码中进行测试。
另请注意,在调用被测代码之前,我需要设置我的模拟。