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

In pytest, what is the use of conftest.py files?

我最近发现了pytest。看起来很棒。但是,我觉得文档可能会更好。

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

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

我有两个问题:

  1. 这是 conftest.py 的正确用法吗?它还有其他用途吗?
  2. 我可以拥有多个 conftest.py 文件吗?我什么时候想这样做?示例将不胜感激。

更一般地说,您将如何在 py.test 测试套件中定义 conftest.py 文件的目的和正确使用?

广义上 conftest.py 是一个本地目录插件。在这里您可以定义目录特定的挂钩和固定装置。在我的例子中,有一个包含项目特定测试目录的根目录。一些常用魔法驻扎在'root'conftest.py。项目特定 - 在他们自己的项目中。在 conftest.py 中存储固定装置没有什么不好,除非它们没有被广泛使用(在那种情况下,我更喜欢直接在测试文件中定义它们)

Is this the correct use of conftest.py?

是的。 Fixtures 是 conftest.py 的潜在和常见用途。这 您将定义的固定装置将在您的测试套件中的所有测试之间共享。但是,在根 conftest.py 中定义固定装置可能没有用,如果所有测试都没有使用此类固定装置,它会减慢测试速度。

Does it have other uses?

是的。

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

  • 外部插件加载: conftest.py用于导入外部插件或mod规则。通过定义以下全局变量,pytest 将加载 module 并使其可用于测试。插件通常是在您的项目或您的测试中可能需要的其他 mod 规则中定义的文件。您还可以按照 here.

    的说明加载一组预定义的插件

    pytest_plugins = "someapp.someplugin"

  • Hooks:您可以指定挂钩,例如设置和拆卸方法等,以改进您的测试。对于一组可用的钩子,请阅读 Hooks link。示例:

      def pytest_runtest_setup(item):
           """ called before ``pytest_runtest_call(item). """
           #do some stuff`
    
  • 测试根路径:这是一个有点隐藏的功能。通过在您的根路径中定义 conftest.py,您将 pytest 识别您的应用程序 mod 规则,而无需指定 PYTHONPATH。在后台,py.test mod通过包含从根路径找到的所有子mod规则来确定您的sys.path

Can I have more than one conftest.py file?

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

When would I want to do that? Examples will be appreciated.

几个案例可能适合:

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

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"

正在为某些测试加载一组 fixtures,但不为其他测试加载。

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中的任何测试,只打印“我是mod”。

您可以阅读更多关于 conftest.py here

编辑:

What if I need plain-old helper functions to be called from a number of tests in different modules - will they be available to me if I put them in a conftest.py? Or should I simply put them in a helpers.py module and import and use it in my test modules?

您可以使用 conftest.py 来定义您的助手。但是,您应该遵循惯例。至少在 pytest 中,助手可以用作固定装置。例如,在我的测试中,我有一个模拟的 redis 助手,我以这种方式将其注入到我的测试中。

root/helper/redis/redis.py

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

root/tests/stuff/conftest.py

pytest_plugin="helper.redis.redis"

root/tests/stuff/test.py

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

这将是一个测试 mod 您可以在测试中自由导入的规则。 注意 如果您的 module redis 包含更多测试,您可以将 redis.py 命名为 conftest.py。但是,由于含糊不清,不鼓励这种做法。

如果你想使用 conftest.py,你可以简单地把那个助手放在你的根 conftest.py 中,并在需要的时候注入它。

root/tests/conftest.py

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

root/tests/stuff/test.py

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

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

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

root/tests/helper/redis.py

class MockRedis():
    # stuff

root/tests/stuff/test.py

from helper.redis import MockRedis

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

但是,由于 module 不在测试的子文件夹中,您可能会遇到路径问题。您应该能够通过向您的助手

添加 __init__.py 来克服这个问题(未经测试)

root/tests/helper/init.py

from .redis import MockRedis

或者只是将助手 module 添加到您的 PYTHONPATH

I use the conftest.py file to define the fixtures that I inject into my tests, is this the correct use of conftest.py?

是的,一个fixture通常用于为多个测试准备好数据

Does it have other uses?

是的,一个fixture就是之前pytest运行的一个函数,有时 之后,实际测试功能。 fixture 中的代码可以做任何你想做的事 想要它。例如,fixture 可用于获取要进行的测试的数据集,或者 fixture 也可用于在 运行 进行测试之前使系统进入已知状态。

Can I have more than one conftest.py file? When would I want to do that?

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

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

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

这里是关于使用conftest.py to share fixtures的官方文档:

conftest.py: sharing fixtures across multiple files

The conftest.py file serves as a means of providing fixtures for an entire directory. Fixtures defined in a conftest.py can be used by any test in that package without needing to import them (pytest will automatically discover them).

You can have multiple nested directories/packages containing your tests, and each directory can have its own conftest.py with its own fixtures, adding on to the ones provided by the conftest.py files in parent directories.