在pytest中,conftest.py文件有什么用?


216

我最近发现了pytest。好像很棒 但是,我认为文档可能会更好。

我正在尝试了解conftest.py文件的用途。

在我的(目前很小的)测试套件conftest.py中,项目根目录下有一个文件。我用它来定义要注入测试的灯具。

我有两个问题:

  1. 这是正确的用法conftest.py吗?它还有其他用途吗?
  2. 我可以有多个conftest.py文件吗?我什么时候要这么做?示例将被理解。

更一般而言,您如何定义conftest.pypy.test测试套件中的目的和正确使用文件?


8
您在It seems great. However, I feel the documentation could be better.
user9074332

6
是的,文档可能要好得多。我在整个pytest文档中进行了搜索conftest.py,尽管有很多引用提及使用conftest文件执行此操作或使用conftest文件执行该操作,但文档中没有任何地方表明pytest测试发现时会找到 所有conftest.py文件将在测试收集阶段(运行任何测试之前)运行在其上完成测试发现的目录strucutre 。必须通过实验弄清楚自己。
Daniel Goldfarb

Answers:


287

这是conftest.py的正确用法吗?

是的。治具是潜在的和普遍的使用conftest.py。您将定义的固定装置将在测试套件中的所有测试之间共享。但是,在根目录中定义固定装置conftest.py可能没有用,如果所有测试未使用此类固定装置,则会减慢测试速度。

它还有其他用途吗?

是的,它确实。

  • 夹具:为测试使用的静态数据定义夹具。除非另有说明,否则套件中的所有测试都可以访问此数据。这可能是数据以及将传递给所有测试的模块帮助程序。

  • 外部插件加载conftest.py用于导入外部插件或模块。通过定义以下全局变量,pytest将加载模块并使它可用于其测试。插件通常是在项目或测试中可能需要的其他模块中定义的文件。您还可以按照此处的说明加载一组预定义的插件。

    pytest_plugins = "someapp.someplugin"

  • 挂钩:您可以指定挂钩(例如设置和拆卸方法)以及更多内容来改善测试。有关一组可用的挂钩,请阅读此处。例:

    def pytest_runtest_setup(item):
         """ called before ``pytest_runtest_call(item). """
         #do some stuff`
  • 测试根路径:这是一个隐藏功能。通过conftest.py在根路径中进行定义,pytest无需指定即可识别应用程序模块PYTHONPATH。py.test在后台sys.path通过包含从根路径找到的所有子模块来修改您的文件。

我可以有多个conftest.py文件吗?

是的,您可以,如果测试结构有些复杂,强烈建议您这样做。conftest.py文件具有目录范围。因此,创建有针对性的装置和助手是一个好习惯。

我什么时候要这么做?示例将不胜感激。

几种情况可能适合:

为一组特定的测试创建一组工具或挂钩

root / mod / conftest.py

def pytest_runtest_setup(item):
    print("I am mod")
    #do some stuff


test root/mod2/test.py will NOT produce "I am mod"

加载一组夹具用于某些测试,但不用于其他测试。

root / mod / conftest.py

@pytest.fixture()
def fixture():
    return "some stuff"

root / mod2 / conftest.py

@pytest.fixture()
def fixture():
    return "some other stuff"

root / mod2 / test.py

def test(fixture):
    print(fixture)

将打印“其他一些东西”。

覆盖从根继承的钩子conftest.py

root / mod / conftest.py

def pytest_runtest_setup(item):
    print("I am mod")
    #do some stuff

root / conftest.py

def pytest_runtest_setup(item):
    print("I am root")
    #do some stuff

通过在内部运行任何测试root/mod,仅打印“ I am mod”。

您可以conftest.py 在此处了解更多信息。

编辑:

如果我需要从不同模块中的多个测试中调用普通的辅助函数,该怎么办-如果将它们放在conftest.py中,它们将对我可用吗?还是我应该将它们放在helpers.py模块中,然后在测试模块中导入并使用它?

您可以conftest.py用来定义您的助手。但是,您应该遵循常规做法。辅助工具至少可以在中用作固定装置pytest。例如,在我的测试中,我有一个模拟的redis帮助器,可以通过这种方式将其注入到我的测试中。

根目录/helper/redis/redis.py

@pytest.fixture
def mock_redis():
    return MockRedis()

根/测试/材料/ conftest.py

pytest_plugin="helper.redis.redis"

根/测试/材料/ test.py

def test(mock_redis):
    print(mock_redis.get('stuff'))

这将是一个测试模块,您可以自由地将其导入测试中。注意,您可能会命名redis.pyconftest.py好像您的模块redis包含更多测试一样。但是,由于模棱两可,不鼓励这种做法。

如果要使用conftest.py,只需将该帮助程序放在根目录中conftest.py,并在需要时将其注入。

root / tests / conftest.py

@pytest.fixture
def mock_redis():
    return MockRedis()

根/测试/材料/ test.py

def test(mock_redis):
    print(mock_redis.get(stuff))

您可以做的另一件事是编写一个可安装的插件。在那种情况下,您的助手可以写在任何地方,但是需要定义一个要安装在您的和其他潜在测试框架中的入口点。看到这个

如果您不想使用固定装置,则当然可以定义一个简单的帮助器,并在需要的地方使用普通的旧导入。

root /测试/helper/redis.py

class MockRedis():
    # stuff

根/测试/材料/ test.py

from helper.redis import MockRedis

def test():
    print(MockRedis().get(stuff))

但是,由于模块不在测试的子文件夹中,因此此处可能存在路径问题。您应该能够克服这(未测试)通过添加__init__.py到您的帮助

root / tests / helper / __ init__.py

from .redis import MockRedis

或者只是将helper模块添加到您的中PYTHONPATH


我遇到的情况是,我的第一个单元测试模块test_aaaaa.py实际上是在夹具安装完成之前尝试运行conftest.py。关于为什么会发生这种情况的任何想法?
user9074332

没有conftest.py,您的测试根路径不会添加到sys.path中,并且您将看到类似“ ModuleNotFoundError:No module named'foobar'”的错误。
Cale Sweeney

10

广义上,conftest.py是一个本地的按目录的插件。在这里,您可以定义目录特定的挂钩和固定装置。在我的情况下,有一个根目录,其中包含项目特定的测试目录。某些常见的魔术位于“ root” conftest.py中。特定于项目-在自己的项目中。除非将夹具广泛使用(在这种情况下,我宁愿直接在测试文件中定义它们),否则在conftest.py中存储夹具时不会发现任何不良情况。


10

我使用该conftest.py文件来定义要注入测试中的灯具,这是否正确使用conftest.py

是的,通常使用固定装置来准备好用于多个测试的数据。

它还有其他用途吗?

是的,灯具是pytest在实际测试功能之前(有时是之后)运行的功能。灯具中的代码可以执行您想要的任何操作。例如,夹具可以用于获取要进行测试的数据集,或者夹具也可以用于在运行测试之前使系统进入已知状态。

我可以有多个conftest.py文件吗?我什么时候要这么做?

首先,可以将灯具放入单独的测试文件中。但是,要在多个测试文件之间共享灯具,您需要在conftest.py所有测试的中央位置使用文件。灯具可以通过任何测试共享。如果您希望夹具仅由该文件中的测试使用,则可以将它们放在单独的测试文件中。

其次,可以,您可以conftest.py在top tests目录的子目录中拥有其他文件。如果这样做,这些较低级别conftest.py文件中定义的固定装置将可用于该目录和子目录中的测试。

最后,将固定装置放在conftest.py文件中的测试根目录下将使它们在所有测试文件中均可用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.