简体   繁体   English

如何使用 pytest 对本地导入的模块进行猴子补丁以进行 Python 测试?

[英]How to monkeypatch locally imported module for Python testing with pytest?

I am working with a very large project and there are already a lot of test that use pytest 's monkeypatch fixture.我正在处理一个非常大的项目,并且已经有很多使用pytestmonkeypatch夹具的测试。 I wish to patch a specific method from a class which belongs to an imported module for example:我希望从属于导入模块的类中修补特定方法,例如:

from project.common import services

in the services package there is a class with a method I wish to patch for example:在服务包中有一个类,其中包含我希望修补的方法,例如:

services.utils.Calculations.get_area()

I try to mock and monkeypatch it:我尝试mockmonkeypatch

mocked_get_area_method= Mock(return_value=500)
monkeypatch.setattr(
   'services.utils.Calculations.get_area',
    mocked_get_user_ip_method,
)

then I create an object in my test:然后我在我的测试中创建一个对象:

class TestCommon:
    def test_calculations(self,monkeypatch):
        mocked_get_area_method= Mock(return_value=500)
        monkeypatch.setattr(
           'services.utils.Calculations.get_area',
            mocked_get_user_ip_method,
        )
        calculations = services.utils.Calculations()
        calculations.get_area()
        mocked_get_user_ip_method.assert_called_once()

but I get an error saying: ModuleNotFoundError: No module named 'services'.但我收到一条错误消息: ModuleNotFoundError: No module named 'services'.

I believe the error comes form the fact that maybe monkeypatch looks for objects starting from the high level main project folder.我相信错误来自这样一个事实,即可能是monkeypatch从高级主项目文件夹开始查找对象。 If i try to monkeypath with this path:如果我尝试使用这条路径进行monkeypath路径:

        monkeypatch.setattr(
           'project.common.services.utils.Calculations.get_area',
            mocked_get_user_ip_method,
        )

the monkeypatching works BUT then I dont get a True in my assert because I believe the monkeypatching has changed the object in the main projects but since I have already imported it and instantiate the services.utils.Calculations() from the locally imported module the patching does not work. monkeypatching 工作但我没有在我的assert中得到True因为我相信 monkeypatching 已经改变了主要项目中的对象但是因为我已经导入它并从本地导入的模块实例化services.utils.Calculations()补丁不起作用。

How can I make this work?我怎样才能使这项工作?

Note: The pytest is run from the main project directory.注意: pytest 从主项目目录运行。

You need to apply the patch to the module that has the from project.common import services statement.您需要将补丁应用于具有from project.common import services语句的模块。 So for example, assume I have a file project/frontend.py that looks like this:例如,假设我有一个文件project/frontend.py ,如下所示:

from project.common import services


def a_method():
    calc = services.utils.Calculations()
    return calc.get_area()

I'd like to test that a_method correctly returns whatever value it receives from the get_area() call, so in tests/test_frontend.py I might write:我想测试a_method是否正确返回它从get_area()调用接收到的任何值,所以在tests/test_frontend.py我可能会写:

import project.frontend

from unittest import mock


def test_a_method(monkeypatch):
    fake_get_area = mock.Mock(return_value=2.0)

    monkeypatch.setattr(
        project.frontend.services.utils.Calculations, "get_area", fake_get_area
    )

    res = project.frontend.a_method()

    assert res == 2.0

Here, we're patching project.frontend.services.utils.Calculations because we've imported project.frontend and frontend.py imports the project.common.services as the name services .在这里,我们正在修补project.frontend.services.utils.Calculations因为我们已经导入了project.frontend并且frontend.py导入了project.common.services作为名称services

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM