[英]How can I mock an object instantiated in the constructor?
I'm writing unit-tests with Pytest. 我正在用Pytest编写单元测试。 I want to unit-test a class that has on its
__init__
method an object that connects to a database: 我想对在其
__init__
方法上具有连接到数据库的对象的类进行单元测试:
data_model.py data_model.py
from my_pkg.data_base_wrapper import DataBaseWrapper
class DataModel:
def __init__(self):
self.db = DataBaseWrapper()
self.db.update_data()
def foo(self):
data = self.db.get_some_data()
# make some processing and return a result
data_base_wrapper.py data_base_wrapper.py
class DataBaseWrapper:
def __init__(self):
# Init process of the wrapper
pass
def update_data(self):
# Connect to the database and perform some operations
pass
I've tried using monkeypatch
on the DataBaseWrapper
object of DataModel
: 我试过在
DataModel
的DataBaseWrapper
对象上使用monkeypatch
:
from my_pkg.data_model import DataModel
class MockDataBaseWrapper:
@staticmethod
def update_cache():
pass
@staticmethod
def get_table(table):
# Return some data for testing
pass
@pytest.fixture
def data_model(monkeypatch):
monkeypatch.setattr(DataModel, 'db', MockDataBaseWrapper)
data_model = DataModel()
return data_model
However, I get the following error: 但是,出现以下错误:
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f10221669e8>
@pytest.fixture
def data_model(monkeypatch):
> monkeypatch.setattr(DataModel, 'db', MockDataBaseWrapper)
E AttributeError: <class 'dashboard.datamodel.DataModel'> has no attribute 'db'
I've read in the answers of similar questions, that I could try writing a sub-class of my DataBaseWrapper
and change it on the DataModel
class, but I'm in the same situation, as I cannot monkeypatch
the attribute of the __init__
method. 我已经读过类似问题的答案,我可以尝试编写
DataBaseWrapper
的子类并在DataModel
类上进行更改,但我处在相同的情况下,因为我无法对__init__
方法的属性进行monkeypatch
。 I can, though, if it is not in the __init__
method. 但是,如果不在
__init__
方法中,则可以。
How can I write tests for this composition of classes? 我该如何为此类课程编写测试? Suggestions on how to rewrite these classes or a different patter are also welcome.
也欢迎提出有关如何重写这些类或不同模式的建议。
The problem is that your MockDataBaseWrapper
is totally unrelated to the DataBaseWrapper
used in DataModel
. 问题是您的
MockDataBaseWrapper
与DataModel
使用的DataBaseWrapper
完全无关。
My proposal is to get rid of your MockDataBaseWrapper
and: 我的建议是摆脱
MockDataBaseWrapper
并:
patch
to mock the DataBaseWrapper
that is actually imported in data_model.py. patch
来模拟实际导入到data_model.py中的DataBaseWrapper
。 from mock import patch
from my_pkg.data_model import DataModel
def test_data_model():
with patch("my_pkg.data_model.DataBaseWrapper") as MockedDB:
mocked_db = MockedDB()
data_model = DataModel()
assert data_model.db is mocked_db
The patch
context manager will replace the DataBaseWrapper
class that gets imported in your data_model.py with a Mock instance and let you interact with that mock, which allows me here to verify that it got instantiated. patch
上下文管理器将使用Mock实例替换在data_model.py中导入的DataBaseWrapper
类,并让您与该模拟进行交互,这使我在此处可以验证它是否已实例化。
Note that it is very important to patch the class in the module where it is imported (and not in the model where it is defined, ie we patch
your_package.data_model.DataBaseWrapper
and notyour_package.data_base_wrapper.DataBaseWrapper
)请注意,在导入该模块的模块中修补该类非常重要(而不是在定义该模块的模型中进行修补,即我们修补
your_package.data_model.DataBaseWrapper
而不是your_package.data_base_wrapper.DataBaseWrapper
)
db
parameter into the constructor of DataModel
. db
参数注入DataModel
的构造函数中。 Mocking it then becomes a piece of cake. class DataModel:
def __init__(self, db):
self.db = db
self.db.update_data()
from mock import patch, Mock
from my_pkg.data_model import DataModel
def test_data_model():
mocked_db = Mock()
data_model = DataModel(mocked_db)
assert data_model.db is mocked_db
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.