在特定的 pytest 标记上禁用 autouse fixtures

Disable autouse fixtures on specific pytest marks

是否可以阻止仅在特定标记上执行 autouse=True 的 "function scoped" 固定装置?

我将以下装置设置为自动使用,以便自动模拟所有传出请求:

@pytest.fixture(autouse=True)
def no_requests(monkeypatch):
    monkeypatch.setattr("requests.sessions.Session.request", MagicMock())

但我有一个名为 endtoend 的标记,我用它来定义一系列测试,这些测试允许发出外部请求以进行更稳健的端到端测试。我想在所有测试(绝大多数)中注入 no_requests,但不会在如下测试中注入:

@pytest.mark.endtoend
def test_api_returns_ok():
    assert make_request().status_code == 200

这可能吗?

我无法找到一种方法来禁用 autouse=True 的装置,但我确实找到了一种方法来恢复在我的 no_requests 装置中所做的更改。 monkeypatch 有一个方法 undo 可以恢复堆栈上的所有补丁,所以我可以在我的端到端测试中调用它,如下所示:

@pytest.mark.endtoend
def test_api_returns_ok(monkeypatch):
    monkeypatch.undo()
    assert make_request().status_code == 200

取消或更改自动使用会很困难,而且可能不可能

您不能取消自动使用,因为它是自动使用。也许你可以做一些事情来根据标记的条件改变自动使用的夹具。但这将是骇人听闻的和困难的。

可能与:

import pytest
from _pytest.mark import MarkInfo

我找不到执行此操作的方法,但也许 @pytest.fixture(autouse=True) 可以获得 MarkInfo,如果它返回 'endtoend' 夹具将不会设置该属性。但是您还必须在夹具参数中设置条件。

即:@pytest.fixture(True=MarkInfo, autouse=True)。像那样的东西。但是我找不到办法。


建议您组织测试以防止这种情况发生

您可以通过以下任一方式将 no_requests 与端到端测试分开:

  1. 限制自动使用夹具的范围
  2. 将no_requests放入class
  3. 不要让它自动使用,只需将它传递给每个你需要的定义的参数

像这样:

class NoRequests:
    @pytest.fixture(scope='module', autouse=True)
    def no_requests(monkeypatch):
        monkeypatch.setattr("requests.sessions.Session.request", MagicMock())
    def test_no_request1(self):
        # do stuff here
    # and so on

这是很好的做法。也许其他组织可以提供帮助


但在您的情况下,monkeypatch.undo()

可能是最简单的

您还可以使用夹具中的 request object 检查测试中使用的标记,如果设置了特定标记,则不要执行任何操作:

import pytest

@pytest.fixture(autouse=True)
def autofixt(request):
    if 'noautofixt' in request.keywords:
        return
    print("patching stuff")

def test1():
    pass

@pytest.mark.noautofixt
def test2():
    pass

输出 -vs:

x.py::test1 patching stuff
PASSED
x.py::test2 PASSED

如果您在特定模块或 类 中进行了 endtoend 测试,您也可以只 override 本地 no_requests 夹具,例如假设您将所有在名为 end_to_end.py:

的文件中进行集成测试
# test_end_to_end.py

@pytest.fixture(autouse=True)
def no_requests():
    return

def test_api_returns_ok():
    # Should make a real request.
    assert make_request().status_code == 200