Mock patch 在 __init__.py 中对类无效

13 投票
1 回答
4806 浏览
提问于 2025-04-17 10:43

我正在尝试使用补丁(patch)来在一个方法中返回一个模拟对象(Mock)。基本结构如下:

MyCode.py

class MyClass:

    def __init__(self, first_name, last_name):
        self.first = first_name
        self.last = last_name

    def get_greeting(self):
        return 'Hello {f} {l}'.format(f=self.first, l=self.last)


def get_new_greeting(first_name, last_name):
    obj = MyClass(first_name, last_name)
    return obj.get_greeting()


my_code_test.py

import unittest
from mock import Mock, patch
import my_code

class TestMyCode(unittest.TestCase):
    def setUp(self):
        pass

    @patch('my_code.MyClass')
    def test_get_greeting(self, MockClass):
        instance = MockClass.return_value
        mock_greeting = 'Hello Me'
        instance.get_greeting.return_value = mock_greeting

        greeting = my_code.get_new_greeting('john', 'doe')
        self.assertEqual(greeting, mock_greeting)


if __name__ == '__main__':
    unittest.main()

上面的代码对我来说运行得很好。不过,当我把同样的方式应用到我想要测试的真实代码时,测试的方法中返回的却是实际对象(而不是模拟对象)。我看不出有什么不同。唯一有点不同的是,真实的类是在一个init.py文件中定义的。我不确定这是否会有影响?有没有人遇到过这种情况?

注意:实际使用的库是twilio 3.3.5,我使用的是Python 2.6.5、Django 1.3.1和Mock 0.7.2。

1 个回答

11

我搞明白了。这和 __init__.py 文件没有关系。问题完全是我自己的错! :)

为了帮助将来有需要使用 Mock 和 patch 结合 Twilio 和短信的人,这里有个解决方案:

我在模拟类 twilio.rest.TwilioRestClient,但事情是有层次关系的,我需要在内部类 SmsMessage 上调用 patch。所以,在我的单元测试中,这样做效果很好:

@patch('twilio.rest.resources.SmsMessages')
def test_send_msg_valid_args(self, MockClass):
    instance = MockClass.return_value
    instance.create.return_value = None
    to_number = '+15555555555'
    msg = 'Hello world'
    send_sms(to_number, msg)

    instance.create.assert_called_once_with(to=to_number, body=msg, from_=default_from_number)

注意:send_sms 实际上是我想测试的函数。我只是想确保它按预期调用了 Twilio,并提供了 default_from_number。default_from_number 的值是在设置文件中定义的,对于这个例子来说并不是特别重要。

撰写回答