如何在pytest中全局打补丁?
How to patch globally in pytest?
我的代码经常使用 pytest。示例代码结构如下所示。整个代码库是 python-2.7
core/__init__.py
core/utils.py
#feature
core/feature/__init__.py
core/feature/service.py
#tests
core/feature/tests/__init__.py
core/feature/tests/test1.py
core/feature/tests/test2.py
core/feature/tests/test3.py
core/feature/tests/test4.py
core/feature/tests/test10.py
service.py
看起来像这样:
from modules import stuff
from core.utils import Utility
class FeatureManager:
# lots of other methods
def execute(self, *args, **kwargs):
self._execute_step1(*args, **kwargs)
# some more code
self._execute_step2(*args, **kwargs)
utility = Utility()
utility.doThings(args[0], kwargs['variable'])
feature/tests/*
中的所有测试最终都使用了 core.feature.service.FeatureManager.execute
函数。但是 utility.doThings()
对我来说 运行 并不是必须的,而我正在 运行 进行测试。我需要它在生产应用程序 运行s 时发生,但我不希望它在测试 运行.
时发生
我可以在 core/feature/tests/test1.py
中做这样的事情
from mock import patch
class Test1:
def test_1():
with patch('core.feature.service.Utility') as MockedUtils:
exectute_test_case_1()
这行得通。但是,我刚刚将 Utility
添加到代码库中,并且我有 300 多个测试用例。我不想进入每个测试用例并编写此 with
语句。
我可以写一个 conftest.py
来设置一个 os 级别的环境变量 core.feature.service.FeatureManager.execute
可以根据该变量决定不执行 utility.doThings
但我不知道如果这是解决此问题的干净方法。
如果有人可以帮助我对整个会话进行全局修补,我将不胜感激。我想在整个会话中全局执行我对上面 with
块所做的操作。这方面的任何文章也都很棒。
TLDR:如何在 运行ning pytests 时创建会话范围的补丁?
我添加了一个名为 core/feature/conftest.py
的文件,看起来像这样
import logging
import pytest
@pytest.fixture(scope="session", autouse=True)
def default_session_fixture(request):
"""
:type request: _pytest.python.SubRequest
:return:
"""
log.info("Patching core.feature.service")
patched = mock.patch('core.feature.service.Utility')
patched.__enter__()
def unpatch():
patched.__exit__()
log.info("Patching complete. Unpatching")
request.addfinalizer(unpatch)
这并不复杂。就像做
with mock.patch('core.feature.service.Utility') as patched:
do_things()
但仅限于会话范围内。
在 for a similar use case (4.5 years later), using unittest.mock's patch
的基础上使用 yield
也有效:
from typing import Iterator
from unittest.mock import patch
import pytest
@pytest.fixture(scope="session", autouse=True)
def default_session_fixture() -> Iterator[None]:
log.info("Patching core.feature.service")
with patch("core.feature.service.Utility"):
yield
log.info("Patching complete. Unpatching")
一边
我没有使用 autouse=True
,我使用 @pytest.mark.usefixtures("default_session_fixture")
在逐个测试的基础上将其集成到我的单元测试中。
版本
Python==3.8.6
pytest==6.2.2
我的代码经常使用 pytest。示例代码结构如下所示。整个代码库是 python-2.7
core/__init__.py
core/utils.py
#feature
core/feature/__init__.py
core/feature/service.py
#tests
core/feature/tests/__init__.py
core/feature/tests/test1.py
core/feature/tests/test2.py
core/feature/tests/test3.py
core/feature/tests/test4.py
core/feature/tests/test10.py
service.py
看起来像这样:
from modules import stuff
from core.utils import Utility
class FeatureManager:
# lots of other methods
def execute(self, *args, **kwargs):
self._execute_step1(*args, **kwargs)
# some more code
self._execute_step2(*args, **kwargs)
utility = Utility()
utility.doThings(args[0], kwargs['variable'])
feature/tests/*
中的所有测试最终都使用了 core.feature.service.FeatureManager.execute
函数。但是 utility.doThings()
对我来说 运行 并不是必须的,而我正在 运行 进行测试。我需要它在生产应用程序 运行s 时发生,但我不希望它在测试 运行.
我可以在 core/feature/tests/test1.py
from mock import patch
class Test1:
def test_1():
with patch('core.feature.service.Utility') as MockedUtils:
exectute_test_case_1()
这行得通。但是,我刚刚将 Utility
添加到代码库中,并且我有 300 多个测试用例。我不想进入每个测试用例并编写此 with
语句。
我可以写一个 conftest.py
来设置一个 os 级别的环境变量 core.feature.service.FeatureManager.execute
可以根据该变量决定不执行 utility.doThings
但我不知道如果这是解决此问题的干净方法。
如果有人可以帮助我对整个会话进行全局修补,我将不胜感激。我想在整个会话中全局执行我对上面 with
块所做的操作。这方面的任何文章也都很棒。
TLDR:如何在 运行ning pytests 时创建会话范围的补丁?
我添加了一个名为 core/feature/conftest.py
的文件,看起来像这样
import logging
import pytest
@pytest.fixture(scope="session", autouse=True)
def default_session_fixture(request):
"""
:type request: _pytest.python.SubRequest
:return:
"""
log.info("Patching core.feature.service")
patched = mock.patch('core.feature.service.Utility')
patched.__enter__()
def unpatch():
patched.__exit__()
log.info("Patching complete. Unpatching")
request.addfinalizer(unpatch)
这并不复杂。就像做
with mock.patch('core.feature.service.Utility') as patched:
do_things()
但仅限于会话范围内。
在 patch
的基础上使用 yield
也有效:
from typing import Iterator
from unittest.mock import patch
import pytest
@pytest.fixture(scope="session", autouse=True)
def default_session_fixture() -> Iterator[None]:
log.info("Patching core.feature.service")
with patch("core.feature.service.Utility"):
yield
log.info("Patching complete. Unpatching")
一边
我没有使用 autouse=True
,我使用 @pytest.mark.usefixtures("default_session_fixture")
在逐个测试的基础上将其集成到我的单元测试中。
版本
Python==3.8.6
pytest==6.2.2