我要修补一个类(Cat)和一个方法(say_hello)。当我仅修补课程时,一切正常。当我仅修补该方法时,它也起作用。当我同时修补两个时,该类未修补,但该方法已正确修补。
main.py
from hello import say_hello
from cat import Cat
cat = Cat('kitty')
def main():
print(say_hello())
hello.py
def say_hello():
return "No mocked"
test.py
import unittest
from unittest.mock import patch
class TestStringMethods(unittest.TestCase):
# cat.Cat is not patched correctly if both patch statements are there
@patch('cat.Cat')
@patch('main.say_hello')
def test_kitty(self, say_hello_mock, cat_mock):
say_hello_mock.return_value = "Mocked"
from main import main
main()
if __name__ == '__main__':
unittest.main()
如果运行前面的示例,则会创建一个真实的Cat。如果您评论main.say_hello的补丁,则会创建一个模拟猫。
答案 0 :(得分:1)
我不知道为什么补丁装饰器不起作用,但是您可以使用以下解决方案:
def test_kitty(self):
with patch('cat.Cat') as cat_mock:
with patch('main.say_hello') as hello_mock:
from main import main
main()
答案 1 :(得分:1)
在我的问题上,第一个称为main.say_hello的补丁。我将触发主模块的导入,并且cat将被实例化为真实的Cat实例。然后,猫被打补丁,但为时已晚。
技巧是反转补丁的顺序:
@patch('main.say_hello')
@patch('cat.Cat')
def test_kitty(self, cat_mock, say_hello_mock):
say_hello_mock.return_value = "Mocked"
from main import main
main()
当装饰器以向外的顺序调用时,将修补Cat,然后修补say_hello,从而触发主模块的导入(实例化模拟的Cat)。
答案 2 :(得分:0)
@patch('cat.Cat')
调用将首先导入cat
模块。此时,cat.cat
对象是从原始Cat
类创建的,它将引用此原始类作为其类型。
现在,您将{<1>}的原始引用替换为对模拟的引用。这对对象不再有影响。
您对类的属性或方法进行了修补,实例将被间接更改,但是替换引用会使原始类保持不变。
答案 3 :(得分:0)
say_hello()
是在hello.py
中定义的,因此:
@patch('main.say_hello')
应更改为:
@patch('hello.say_hello')
然后您可以决定首先在装饰器中模拟哪个。