此问题在此处已有答案:
Python Mocking a function from an imported module(3个答案)
5年前关闭。
我想测试我写的一个邮件发送方法。在文件format_email.py中导入send_email。
from cars.lib.email import send_email
class CarEmails(object):
def __init__(self, email_client, config):
self.email_client = email_client
self.config = config
def send_cars_email(self, recipients, input_payload):
在send_汽车_email()中格式化电子邮件内容后,我使用前面导入的方法发送电子邮件。
response_code = send_email(data, self.email_client)
在我的测试文件test_car_email.py中
@pytest.mark.parametrize("test_input,expected_output", test_data)
def test_email_payload_formatting(test_input, expected_output):
emails = CarsEmails(email_client=MagicMock(), config=config())
emails.send_email = MagicMock()
emails.send_cars_email(*test_input)
emails.send_email.assert_called_with(*expected_output)
当我运行测试时,它在Assert未被调用时失败。我相信问题出在我嘲笑send_email函数的地方。
我应该在哪里模拟这个函数呢?
3条答案
按热度按时间wxclj1h51#
既然您使用的是pytest,我建议您使用pytest内置的'monkeypatch' fixture。
考虑以下简单设置:
我们定义要模拟的函数。
和调用该函数的类放在一个单独的文件中。
我们使用“monkeypatch”fixture模拟函数的使用位置
如果您想重用它,我们还可以将mock分解到它自己的fixture中。
4c8rllxm2#
您使用
emails.send_email = MagicMock()
行模拟的是函数这一行只会向
emails
对象 * 添加 * 一个新函数。然而,这个函数不是从代码中调用的,赋值也不会有任何效果。相反,你应该模拟cars.lib.email
模块中的send_email
函数。模拟使用它的函数
一旦你通过
from cars.lib.email import send_email
将函数send_email
导入到你的模块format_email.py
中,它就可以用format_email.send_email
这个名字了,因为你知道这个函数是在那里被调用的,所以你可以用它的新名字模拟它:模拟定义函数的位置
更新:
阅读
unittest
文档中的Where to patch一节确实很有帮助(也可以参见Martijn Pieters的注解):基本原则是在查找对象的位置打补丁,而查找对象的位置不一定与定义对象的位置相同。
因此,请坚持在使用位置模拟函数,不要从刷新导入或按正确的顺序对齐它们开始,即使可能会出现一些模糊的用例,即由于某种原因无法访问
format_email
的源代码(就像当它是一个cythonized/compiled C/C++扩展模块时),您仍然只有两种可能的导入方法,因此,只需尝试两种模拟可能性,如在何处打补丁中所述,并使用成功的一种。原答复:
你也可以在
send_email
的原始模块中模拟它:但请注意,如果您在打补丁之前在
format_email.py
中调用了send_email
的导入,则打补丁cars.lib.email
不会对format_email
中的代码产生任何影响,因为函数已经导入,因此不会调用以下示例中的mocked_send
:要解决此问题,您应该在
cars.lib.email
修补程序之后首次导入format_email
:或重新加载模块,例如使用
importlib.reload()
:如果你问我的话,这两种方法都不怎么样,我会坚持在调用函数的模块中模拟函数。
o2gm4chl3#
最简单的修复方法如下
基本上,您有一个已经在
format_email
中导入了send_email
的模块,现在必须更新加载的模块。但这不是最推荐的方法,因为你会失去原来的
send_email
函数,所以你应该使用上下文补丁,有不同的方法可以做到这一点方式1
在这里,我们模拟导入的实际函数
第二条路
这样,文件中的任何测试都可以将修补函数用于其他测试
路3
在这个方法中,我们修补了导入本身,而不是实际被调用的函数。在这种情况下,不需要重载
所以你可以看到有不同的方式来做嘲弄,一些方法来作为良好的做法,一些来作为个人的选择