问题描述
我的代码结构如下:
我有一个从 BaseClass
继承的 MyClass
类(这是一个偶然的点,而不是我的问题的根源).然后我有另一个类 MyClassManager
调用 MyClass
的方法.
I have a class MyClass
that inherits from BaseClass
(this is an incidental point and not the source of my problem). Then I have another class MyClassManager
that calls the methods of MyClass
.
我正在为 MyClassManager
的方法编写单元测试,我想控制 MyClass
方法之一的返回值,同时自动指定其余方法.
I am writing a unittest for a method of MyClassManager
and I want to control the return value of one of the methods of MyClass
while autospeccing the rest.
在我的测试中,我通过使用 autospec=True
修补类,为 MyClass
创建了一个 Mock.然后我尝试修补方法 MyClass.method_to_patch
并将其替换为 Substitute.substitute_method
.到目前为止,一切都很好.
In my test I have created a Mock for MyClass
by patching the class with autospec=True
. Then I have tried to patch the method MyClass.method_to_patch
and replace it with Substitute.substitute_method
. So far, so good.
但是现在当我运行测试时,类管理器创建了一个 MyClass
的实例,它是一个完全自动指定的 Mock,但它没有修补我想要替换的方法.
But now when I run the test, the class manager creates an instance of MyClass
that is a fully autospecced Mock, but it doesn't patch the method I want to substitute.
有没有办法结合这两个 patch
装饰器来实现我想要的?
Is there a way to combine these two patch
decorators to achieve what I want?
class Substitute:
def substitute_method(self, arg1, arg2):
print("Running substitute method")
return (arg1 > 0 and arg2 > 0)
class BaseClass:
def method_to_patch(self, arg1, arg2):
return arg1 == arg2
class MyClass(BaseClass):
def myclass_method(self):
print("myclass method called")
class MyClassManager:
def method_to_test(self):
my_class = MyClass()
my_class.myclass_method()
my_class.method_to_patch(10, 100)
class TestMyClass(unittest.TestCase):
@patch.object(MyClass, "method_to_patch", Substitute.substitute_method)
@patch("__main__.MyClass", autospec=True)
def test_method_to_test(self, mock_class):
class_manager = MyClassManager()
class_manager.method_to_test()
print(mock_class.call_count)
if __name__ == "__main__":
unittest.main()
推荐答案
我在下一页找到了答案的线索,其中讨论了模拟嵌套属性调用:https://www.integralist.co.uk/posts/mocking-in-python/.相同的逻辑适用于方法调用.
I found a clue to the answer at the following page where it talks about mocking nested attribute calls: https://www.integralist.co.uk/posts/mocking-in-python/. The same logic applies to method calls.
手动调整模拟对象是不够的 - 你必须调整模拟对象的return_value
.
It is not enough to manually adjust the mocked object - you have to adjust the return_value
of the mocked object.
这里是测试的样子:
class TestMyClass(unittest.TestCase):
@patch("__main__.MyClass", autospec=True)
def test_method_to_test(self, mock_class):
mock_class.return_value.method_to_patch = Substitute.substitute_method
class_manager = MyClassManager()
class_manager.method_to_test()
print(mock_class.call_count)
现在我有一个模拟对象代替了 MyClass
所以 MyClass.myclass_method
也被模拟了,但我可以替换 Substitute.substitute_method
MyClass.method_to_patch
我想要的地方.
Now I have a mock object in place of MyClass
so MyClass.myclass_method
is also mocked, but I can substitute Substitute.substitute_method
in place of MyClass.method_to_patch
as I wanted.
最后一点 - substitute_method
实际上是一个 staticmethod
所以它应该是这样的:
One final note - the substitute_method
is actually a staticmethod
so it should look like this:
class Substitute:
@staticmethod
def substitute_method(arg1, arg2):
print("Running substitute method")
return (arg1 > 0 and arg2 > 0)
这篇关于修补模拟类的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!