首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用conftest.py与从专用模块导入夹具

使用conftest.py与从专用模块导入夹具
EN

Stack Overflow用户
提问于 2022-08-01 09:19:58
回答 2查看 318关注 0票数 3

最近我已经熟悉了pytest,以及如何使用conftest.py来定义在我的测试中自动发现和导入的夹具。我非常清楚conftest.py是如何工作的,以及如何使用它,但我不知道为什么在一些基本场景中这被认为是最佳实践。

假设我的测试是以这种方式构造的:

代码语言:javascript
复制
tests/
--test_a.py
--test_b.py

最好的实践,正如文档和关于web上pytest的各种文章所建议的那样,是定义一个conftest.py文件,其中包含一些在test_a.pytest_b.py中使用的补丁。为了更好地组织我的夹具,我可能需要以语义上有意义的方式将它们分割成单独的文件,例如。db_session_fixtures.pydataframe_fixtures.py,然后将它们作为插件导入conftest.py中。

代码语言:javascript
复制
tests/
--test_a.py
--test_b.py
--conftest.py
--db_session_fixtures.py
--dataframe_fixtures.py

conftest.py中,我应该:

代码语言:javascript
复制
import pytest
    
pytest_plugins = ["db_session_fixtures", "dataframe_fixtures"]

而且我可以在我的测试用例中无缝地使用db_session_fixturesdataframe_fixtures,而不需要任何额外的代码。

虽然这很方便,但我觉得它可能会损害可读性。例如,如果我不像上面描述的那样使用conftest.py,我可能会用test_a.py编写

代码语言:javascript
复制
from .dataframe_fixtures import my_dataframe_fixture

def test_case_a(my_dataframe_fixture):
   #some tests

像往常一样使用固定装置。

缺点是,它要求我导入夹具,但显式导入提高了测试用例的可读性,让我像其他python模块一样,一目了然地知道夹具来自何处。

我是否忽略了这个解决方案或conftest.py带来的其他优点,使其成为设置pytest测试套件的最佳实践?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-08-02 09:43:20

没有太大的差别,这主要是因为偏好。我主要使用conftest.py来提取所需的补丁,但不是直接由您的测试使用。因此,您可能有一个对数据库有用的工具,但需要一个数据库连接。因此,您可以在db_connection中使用conftest.py夹具,然后您的测试只需执行以下操作:

conftest.py

代码语言:javascript
复制
from tests.database_fixtures import db_connection

__all__ = ['db_connection']

tests/database_fixtures.py

代码语言:javascript
复制
import pytest

@pytest.fixture
def db_connection():
    ...

@pytest.fixture
def new_user(db_connection):
    ...

test/test_user.py

代码语言:javascript
复制
from tests.database_fixtures import new_user

def test_user(new_user):
    assert new_user.id > 0  # or whatever the test needs to do

如果您没有使db_connectionconftest.py中可用或直接导入它,那么pytest在尝试使用new_user夹具时将无法找到db_connection夹具。如果您直接将db_connection导入您的测试文件中,那么指针将抱怨它是一个未使用的导入。更糟糕的是,有些人可能会删除它,并导致您的测试失败。因此,让db_connectionconftest.py中可用,对我来说,是最简单的解决方案。

覆盖固定装置

一个显著的区别是使用conftest.py覆盖固定装置更容易。假设您的目录布局为:

代码语言:javascript
复制
./
├─ conftest.py
└─ tests/
   ├─ test_foo.py
   └─ bar/
      ├─ conftest.py
      └─ test_foobar.py

conftest.py中,您可以拥有:

代码语言:javascript
复制
import pytest

@pytest.fixture
def some_value():
    return 'foo'

然后在tests/bar/conftest.py中你可以得到:

代码语言:javascript
复制
import pytest

@pytest.fixture
def some_value(some_value):
    return some_value + 'bar'

有了多个自白,您可以覆盖一个固定设备,同时仍然保持对原始夹具的访问。所以接下来的测试都会有效。

tests/test_foo.py

代码语言:javascript
复制
def test_foo(some_value):
    assert some_value == 'foo'

tests/bar/test_foobar.py

代码语言:javascript
复制
def test_foobar(some_value):
    assert some_value == 'foobar'

没有conftest.py,您仍然可以做到这一点,但这要复杂一些。你需要做这样的事情:

代码语言:javascript
复制
import pytest

# in this scenario we would have something like:
#   mv contest.py tests/custom_fixtures.py
from tests.custom_fixtures import some_value as original_some_value

@pytest.fixture
def some_value(original_some_value):
    return original_some_value + 'bar'

def test_foobar(some_value):
    assert some_value == 'foobar'
票数 1
EN

Stack Overflow用户

发布于 2022-08-02 08:22:35

对我来说没有根本的区别,从执行的角度来看,无论代码组织如何,结果都是一样的。

代码语言:javascript
复制
pytest --setup-show
# test_a.py 
#         SETUP    F f_a
#         test_a.py::test_a (fixtures used: f_a).
#         TEARDOWN F f_a

因此,这只是一个代码组织的问题,它应该适合您组织代码的方式。

  • 对于小型代码库来说,在单个python文件中定义所有代码是完全可以的,因此使用相同的方法进行测试时,使用单个conftest.py文件。对于更大的代码库,使用
  • ,如果不定义多个模块,将变得非常麻烦。在我看来,测试也是一样的,在这种情况下,如果有意义的话,按模块定义固定设备似乎是非常好的。

避免在测试模块或conftest.py中显式导入补丁的一个变体可能是坚持一个约定(这里假设固定组件由fixture_启动,但它可以是其他所有东西),并在conftest.py中动态导入它。

代码语言:javascript
复制
pytest_plugins = [
    fixture.replace("/", ".").replace(".py", "")
    for fixture in glob(
        "**/fixture_*.py",
        recursive=True
    )
]
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73191533

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档