我有一个ChildX
类,它被许多class Parent(object): # the class that should be mocked
def __init__(self):
assert False # should never happen, because we're supposed to use the mock instead
class Child1(Parent):
def method_1(self):
return 3
class MockParent(object): # this one should replace Parent
def __init__(self):
assert True
类继承。
ChildX
我有一个使用pytest运行的测试套件,我想确保在这些测试期间,每次MockParent
实例化时,实例都会调用Parent
的方法而不是__init__
的(我简化了上面的例子,ChildX
方法并不是唯一有关的方法。)
目前,我所做的就是逐个修补每个class FixturePatcher(object):
def __init__(self, klass):
self.klass = klass
self.patcher = None
def __enter__(self):
self.patcher = mock.patch.object(self.klass, '__bases__', (MockParent,))
return self.patcher.__enter__()
def __exit__(self, *_, **__):
self.patcher.is_local = True
@pytest.fixture()
def mock_parent_on_child1():
with FixturePatcher(Child1):
return Child1()
def test_mock_child1(mock_parent_on_child1):
assert mock_parent_on_child1.method_1() == 3
课程:
ChildX
但是我有很多ChildY
个类,有时会ChildZ
实例化并在Parent
的方法中使用,所以我无法修补它们。
我已经尝试了很多东西来替换MockParent
@mock.patch('src.parent.Parent', MockParent)
def test_mock_parent():
assert Child1().method_1() == 3 # Parent's __init__ method is still called
@mock.patch('src.parent.Parent.__getattribute__', lambda self, name: MockParent.__getattribute__(self, name))
def test_mock_parent():
assert Child1().method_1() == 3 # same results here
def test_mock_parent(monkeypatch):
monkeypatch.setattr('src.parent.Parent', MockParent)
assert Child1().method_1() == 3 # and still the same here
,但没有一个能够奏效。以下是我失败的一些尝试:
pytest
这甚至可能吗?我正在使用python2.7以及mock
和+
的最新版本。
答案 0 :(得分:2)
我想不出用Parent
替换MockParent
到处使用它的地方的方法,但你可以用monkeypatch Parent
的方法代替,如果这就是你的意思后:
class Parent(object):
def my_method(self):
print 'my method'
class Child(Parent):
def run(self):
self.my_method()
child = Child()
child.run() # prints: my method
### Apply the monkeypatch: ###
def my_method(self):
print 'something else'
Parent.my_method = my_method
child.run() # prints: something else
您也可以使用Parent
中的方法以同样的方式对MockParent
的每个方法进行单一操作。这与您更改从Parent
继承的所有内容的父类几乎相同。
修改强>
事实上,如果您搜索Parent
的所有现有子类,修补它们,并且在其模块中将Parent
定义为monkeypatched,那么您可能也可能完全按照您的要求执行操作,以便将来的类也更新了:
for child_class in Parent.__subclasses__():
mock.patch.object(child_class, '__bases__', (MockParent,))
parents_module.Parent = MockParent
我认为这仍然会遗漏一些特殊的情况,所以monkeypatching每个方法可能更好。
答案 1 :(得分:1)
不,这是不可能的。 Child1和Parent的定义 - 包括一个来自另一个的继承 - 在导入它们所在的模块时立即执行。在此之前没有机会进入并更改继承层次结构。
您可以做的最好的事情是将定义移动到某种工厂函数,这可以根据调用的内容动态定义Child1的父级。