奇怪的修补行为

时间:2018-08-21 12:17:15

标签: python unit-testing mocking python-unittest

我要修补一个类(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的补丁,则会创建一个模拟猫。

4 个答案:

答案 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')

然后您可以决定首先在装饰器中模拟哪个。