Pytest 中类范围固定装置的意外行为

viv*_*khi 2 python pytest

我正在学习 pytest 并研究不同固定范围的行为。当我运行测试时,我看到类范围的固定装置的意外行为。这是我的项目结构。

\n
Pytest_Basics\n\xe2\x94\x82   conftest.py\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80pack1\n        test_a.py\n        test_b.py\n
Run Code Online (Sandbox Code Playgroud)\n

以下是每个文件的内容。

\n

测试.py

\n
import pytest\n\n\n@pytest.fixture(scope='session', autouse=True)\ndef ses_fix():\n    print('In session fixture')\n\n\n@pytest.fixture(scope='package', autouse=True)\ndef pak_fix():\n    print('In package fixture')\n\n\n@pytest.fixture(scope='module', autouse=True)\ndef mod_fix():\n    print('In module fixture')\n\n\n@pytest.fixture(scope='class', autouse=True)\ndef cls_fix():\n    print('In class fixture')\n\n\n@pytest.fixture(scope='function', autouse=True)\ndef func_fix():\n    print('In functon fixture')\n
Run Code Online (Sandbox Code Playgroud)\n

测试_a.py

\n
class TestA:\n\n    def test_a1(self):\n        assert True\n\n    def test_a2(self):\n        assert True\n\n    def test_a3(self):\n        assert True\n
Run Code Online (Sandbox Code Playgroud)\n

测试_b.py

\n
def test_b1():\n    assert True\n\n\ndef test_b2():\n    assert True\n\n\ndef test_b3():\n    assert True\n
Run Code Online (Sandbox Code Playgroud)\n

当我使用 运行测试时pytest -v -s。我得到以下输出。

\n
pack1/test_a.py::TestA::test_a1 In session fixture\nIn package fixture\nIn module fixture\nIn class fixture\nIn functon fixture\nPASSED\npack1/test_a.py::TestA::test_a2 In functon fixture\nPASSED\npack1/test_a.py::TestA::test_a3 In functon fixture\nPASSED\npack1/test_b.py::test_b1 In module fixture        \nIn class fixture\nIn functon fixture\nPASSED\npack1/test_b.py::test_b2 In class fixture\nIn functon fixture\nPASSED\npack1/test_b.py::test_b3 In class fixture\nIn functon fixture\nPASSED\n
Run Code Online (Sandbox Code Playgroud)\n

我预计类范围的固定装置只会运行一次,因为我在test_a.py模块中只有一个类。但是,我看到它在test_b.py模块中执行测试时正在运行。

\n

是什么导致了这种行为?这是一个错误还是我对班级级别的装置了解有限。

\n

环境:Python - 3.9.5,Pytest - 6.2.4

\n

MrB*_*men 5

这确实是类范围的装置的行为方式。文档中没有直接提及,但可以从中推断出来。就像声明的那样:

夹具在测试首次请求时创建,并根据其范围销毁

夹具autouse=True应用于会话中的每个测试功能。它们根据其范围被销毁,这意味着基于会话、模块或函数的固定装置在每个测试函数所在的会话、模块或函数结束时被销毁。然而,基于类的固定装置可以在类之外调用,并且为了保持一致,在这种情况下,它们必须在函数之后被销毁 - 否则它们可能永远不会被销毁(如果没有类),或者会跨类边界存在。重要的一点是类范围(或任何其他范围)并不意味着固定装置仅应用于该范围(例如在类内部),而是应用于任何测试函数,并且范围仅在其被销毁时应用。

对于不在类中的函数,类范围的固定装置的行为就像函数范围的固定装置一样,但它们在函数范围的固定装置之前调用,并在基于函数的固定装置之后关闭:

测试.py

@pytest.fixture(scope="function", autouse=True)
def fct_fixt():
    print("function fixture start")
    yield
    print("function fixture end")


@pytest.fixture(scope="class", autouse=True)
def class_fixt():
    print("class fixture start")
    yield
    print("class fixture end")
Run Code Online (Sandbox Code Playgroud)

test_fixt.py

def test_1():
    print("test_1 outside class")

class TestClass:
    def test_1(self):
        print("test_1 inside class")

    def test_class_2(self):
        print("test_2 inside class")
Run Code Online (Sandbox Code Playgroud)
$ python -m pytest -s test_fixt.py

...
class fixture start
  function fixture start
    test_1 outside class
  function fixture end
class fixture end
class fixture start
  function fixture start
    test_1 inside class
  function fixture end
  function fixture start
    test_2 inside class
  function fixture end
class fixture end
Run Code Online (Sandbox Code Playgroud)

(为了清晰起见添加了缩进)