类的 pytest 夹具通过 self 不作为方法参数



通常我会编写一个在每个方法中使用pytest夹具的测试类。下面是一个示例。我希望能够避免在每个方法的签名中写下夹具名称。它不是干燥的。如何做到这一点?

我希望能够通过将夹具作为测试类的属性来访问夹具。在这个例子中,我希望将谷歌夹具视为TestGoogle的一个属性。这可能吗?

from bs4 import BeautifulSoup
import pytest
import requests
@pytest.fixture()
def google():
return requests.get("https://www.google.com")

class TestGoogle:
def test_alive(self, google):
assert google.status_code == 200
def test_html_title(self, google):
soup = BeautifulSoup(google.content, "html.parser")
assert soup.title.text.upper() == "GOOGLE"

当然,只需使用自动使用灯具即可。这是pytest文档中的相关位置。在您的示例中,更改将引入一个额外的夹具(我将其命名为_request_google_page(:

from bs4 import BeautifulSoup
import pytest
import requests
@pytest.fixture()
def google():
return requests.get("https://www.google.com")

class TestGoogle:
@pytest.fixture(autouse=True)
def _request_google_page(self, google):
self._response = google
def test_alive(self):
assert self._response.status_code == 200
def test_html_title(self):
soup = BeautifulSoup(self._response.content, "html.parser")
assert soup.title.text.upper() == "GOOGLE"

您甚至可以完全放下google装置并将代码移动到_request_google_page

@pytest.fixture(autouse=True)
def _request_google_page(self):
self._response = requests.get("https://www.google.com")

请注意,默认情况下,每个测试将调用一次_request_google_page,因此每个测试都将获得新的响应。如果您希望响应初始化一次并在TestGoogle类中的所有测试中重复使用,请调整夹具范围(scope='class'用于_request_google_pagescope='module'scope='session'用于google(。例:

from bs4 import BeautifulSoup
import pytest
import requests

@pytest.fixture(scope='module')
def google():
return requests.get("https://www.google.com")

@pytest.fixture(autouse=True, scope='class')
def _request_google_page(request, google):
request.cls._response = google

class TestGoogle:
def test_alive(self):
assert self._response.status_code == 200
def test_html_title(self):
soup = BeautifulSoup(self._response.content, "html.parser")
assert soup.title.text.upper() == "GOOGLE"

我必须解决类似的问题,而接受的解决方案对类范围的装置不起作用。

我想为每个测试类调用一次夹具,并使用self在测试方法中重用该值。这实际上也是OP打算做的。

您可以使用request装置访问使用它的类(request.cls(,并在类属性中分配夹具值。然后,您可以从self访问此属性。以下是完整的代码片段:

from bs4 import BeautifulSoup
import pytest
import requests
@pytest.fixture(scope="class")
def google(request):
request.cls.google = requests.get("https://www.google.com")

@pytest.mark.usefixtures("google")
class TestGoogle:
def test_alive(self):
assert self.google.status_code == 200
def test_html_title(self):
soup = BeautifulSoup(self.google.content, "html.parser")
assert soup.title.text.upper() == "GOOGLE"

希望这对其他提出这个问题的人有所帮助。

使用conftest.py、夹具和普通类的组合,将所有测试(或模块化测试(共享相同的对象实例

我想分享我的解决方案,它来自 Pytest 文档(目前为 7.2(

模块化:使用夹具功能中的夹具

现在,如果我们将其与conftest.py相结合,这就是我们可以做的: 首先具有此结构(仅显示子模块,并且所有测试都实例化一次对象(


├── conftest.py
├── sub_folder
│   ├── __init__.py
│   └── test_sub_1.py
├── test_1.py
├── test_2.py

这是内容conftest.py

"""tests/conftest.py"""
import pytest

class MockServer():
def get(self, url):
return "hello-world"
class App:
def __init__(self, http_connection):
print("APP CREATED")
self.http_connection = http_connection
@pytest.fixture(scope="session")
def http_connection():
print("HTTP_CONNECTION FIXTURE")
return MockServer()
@pytest.fixture(scope="session")
def app(http_connection):
print("CREATE APP")
return App(http_connection)

测试/test_1.py

class TestClass1:
def test_1(self, app):
http_connection = app.http_connection
assert http_connection.get("my-url") ==  "hello-world"
def test_2(self, app):
http_connection = app.http_connection
assert http_connection.get("my-url") ==  "hello-world"

测试/test_2.py

class TestClass2:
def test_1(self, app):
http_connection = app.http_connection
assert http_connection.get("my-url") ==  "hello-world"
def test_2(self, app):
http_connection = app.http_connection
assert http_connection.get("my-url") ==  "hello-world"

测试/sub_folder/test_sub_1.py

"""tests/sub_folder/test_sub_1.py"""
class TestSubClass1:
def test_sub_1(self, app):
http_connection = app.http_connection
assert http_connection.get("my-url") ==  "hello-world"
def test_sub_2(self, app):
http_connection = app.http_connection
assert http_connection.get("my-url") ==  "hello-world"

现在,让我们运行

pytest -rP

输出应该是这样的

tests/test_1.py::TestClass1::test_1 PASSED                                                                                               [ 16%]
tests/test_1.py::TestClass1::test_2 PASSED                                                                                               [ 33%]
tests/test_2.py::TestClass2::test_1 PASSED                                                                                               [ 50%]
tests/test_2.py::TestClass2::test_2 PASSED                                                                                               [ 66%]
tests/sub_folder/test_sub_1.py::TestSubClass1::test_sub_1 PASSED                                                                         [ 83%]
tests/sub_folder/test_sub_1.py::TestSubClass1::test_sub_2 PASSED                                                                         [100%]
==================================================================== PASSES ====================================================================
______________________________________________________________ TestClass1.test_1 _______________________________________________________________
------------------------------------------------------------ Captured stdout setup -------------------------------------------------------------
HTTP_CONNECTION FIXTURE
CREATE APP
APP CREATED
============================================================== 6 passed in 0.23s ===============================================================

如您所见,通过输出,(HTTP_CONNECTION FIXTURE, CREATE APP, APP CREATED(仅运行一次。当我们需要在所有测试之间共享资源时,这很好。 话虽如此,现在让我们将其与唄头答案结合起来,我只添加测试/test_1.py

测试/test_1.py

"""tests/test_1.py"""
import pytest
class TestClass1:
@pytest.fixture(autouse=True)
def _app(self, app):
self.app = app
def test_1(self):
assert self.app.http_connection.get("my-url") ==  "hello-world"
def test_2(self):
assert self.app.http_connection.get("my-url") ==  "hello-world"

这已经更好了,但我们可以更进一步,让我们有一个 Base 测试类,并让我们的测试继承自它conftest.py

"""tests/conftest.py"""
import pytest

class MockServer():
def get(self, url):
return "hello-world"
class App:
def __init__(self, http_connection):
print("APP CREATED")
self.http_connection = http_connection
@pytest.fixture(scope="session")
def http_connection():
print("HTTP_CONNECTION FIXTURE")
return MockServer()
@pytest.fixture(scope="session")
def app(http_connection):
print("CREATE APP")
return App(http_connection)

class Base:
@pytest.fixture(autouse=True)
def _app(self, app):
self.app = app

现在""测试/test_1.py""可以看起来像

"""tests/test_1.py"""
from conftest import Base
class TestClass1(Base):
def test_1(self):
assert self.app.http_connection.get("my-url") ==  "hello-world"
def test_2(self):
assert self.app.http_connection.get("my-url") ==  "hello-world"

最新更新