嘲笑 parent class
mocking a parent class
我有一个 Parent
class 被很多 ChildX
class 继承。
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
我有一个 运行 的测试套件,带有 pytest,我想确保在这些测试期间,每次实例化 ChildX
时,实例都会调用 MockParent
的方法而不是 Parent
的方法(我简化了上面的示例,__init__
方法不是唯一关注的方法)。
目前,我所能做的就是一个一个地修补每个 ChildX
class:
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
class,有时 ChildY
被实例化并在 ChildZ
的方法中使用,所以我无法修补它们。
我尝试了很多方法来用 MockParent
替换 Parent
,但其中 none 有效。以下是我的一些失败尝试:
@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
这可能吗?我正在使用 python2.7 以及 pytest
和 mock
.
的 up-to-date 版本
不,这不可能。 Child1 和 Parent 的定义——包括彼此的继承——在它们所在的模块被导入后立即执行。在此之前没有机会进入并更改继承层次结构。
您最好的办法是将定义移动到某种工厂函数,它可以根据调用它的方式动态定义 Child1 的父级。
我想不出在任何地方用 MockParent
替换 Parent
的方法,但是你可以用 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
您也可以使用 MockParent
中的方法对 Parent
中的每个方法进行 monkeypatch,方法相同。这几乎与更改从 Parent
.
继承的所有内容的父 class 相同
编辑:
事实上,如果您搜索 Parent
的所有现有子 class,修补它们,如果 Parent
在其模块中,以便将来的 classes 也得到更新:
for child_class in Parent.__subclasses__():
mock.patch.object(child_class, '__bases__', (MockParent,))
parents_module.Parent = MockParent
我认为这仍然会遗漏一些特殊情况,因此对每个方法进行 monkeypatching 可能会更好。
我有一个 Parent
class 被很多 ChildX
class 继承。
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
我有一个 运行 的测试套件,带有 pytest,我想确保在这些测试期间,每次实例化 ChildX
时,实例都会调用 MockParent
的方法而不是 Parent
的方法(我简化了上面的示例,__init__
方法不是唯一关注的方法)。
目前,我所能做的就是一个一个地修补每个 ChildX
class:
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
class,有时 ChildY
被实例化并在 ChildZ
的方法中使用,所以我无法修补它们。
我尝试了很多方法来用 MockParent
替换 Parent
,但其中 none 有效。以下是我的一些失败尝试:
@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
这可能吗?我正在使用 python2.7 以及 pytest
和 mock
.
不,这不可能。 Child1 和 Parent 的定义——包括彼此的继承——在它们所在的模块被导入后立即执行。在此之前没有机会进入并更改继承层次结构。
您最好的办法是将定义移动到某种工厂函数,它可以根据调用它的方式动态定义 Child1 的父级。
我想不出在任何地方用 MockParent
替换 Parent
的方法,但是你可以用 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
您也可以使用 MockParent
中的方法对 Parent
中的每个方法进行 monkeypatch,方法相同。这几乎与更改从 Parent
.
编辑:
事实上,如果您搜索 Parent
的所有现有子 class,修补它们,如果 Parent
在其模块中,以便将来的 classes 也得到更新:
for child_class in Parent.__subclasses__():
mock.patch.object(child_class, '__bases__', (MockParent,))
parents_module.Parent = MockParent
我认为这仍然会遗漏一些特殊情况,因此对每个方法进行 monkeypatching 可能会更好。