在pytest中,conftest.py文件的用途是什么?

我试图理解conftest.py文件是用来做什么的。

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

我有两个问题:

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

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

175606 次浏览

广义上,conftest.py是一个本地每个目录的插件。这里定义了特定于目录的钩子和fixture。在我的例子中,有一个根目录包含项目特定的测试目录。一些常见的魔法位于`根` conftest.py中。具体项目-在他们自己的。在conftest.py中存储fixture不会看到任何不好的东西,除非它们没有被广泛使用(在这种情况下,我更喜欢直接在测试文件中定义它们)

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

是的。fixture是conftest.py的一个潜在且常见的用途。的 您将定义的fixture将在测试套件中的所有测试之间共享。然而,在根conftest.py中定义fixture可能是无用的,如果不是所有测试都使用这些fixture,则会降低测试速度

它还有其他用途吗?

是的。

  • 固定装置:为测试使用的静态数据定义fixture。除非另有指定,否则套件中的所有测试都可以访问此数据。这可以是数据,也可以是将传递给所有测试的模块的帮助程序。

  • 外部插件加载: 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文件具有目录作用域。因此,创建目标fixture和helper是很好的实践。

我想什么时候做呢?例子将不胜感激。

以下几种情况适合:

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

根/国防部/ 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"

为某些测试加载一组固定装置,但不为其他测试加载。

根/国防部/ conftest.py

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

根/ mod2 / conftest.py

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

根/ mod2 / test.py

def test(fixture):
print(fixture)

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

压倒一切的钩子继承自根conftest.py

根/国防部/ conftest.py

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

根/ conftest.py

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

通过在root/mod中运行任何测试,只有“;I am mod"是印刷的。

你可以阅读更多关于conftest.py 在这里

编辑:

如果我需要普通的旧helper函数从一个数字调用 不同模块的测试-如果我把它们放在 它们在一个conftest.py中?或者我应该简单地把它们放在help .py文件中 模块和导入并在我的测试模块中使用它?< / p >

你可以使用conftest.py来定义你的helper。但是,您应该遵循惯例。至少在pytest中,helper可以作为fixture使用。例如,在我的测试中,我有一个模拟的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包含更多的测试,你可以潜在地将redis.py命名为conftest.py。但是,由于模糊性,不鼓励这种做法。

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

根/测试/ conftest.py

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

根/测试/材料/ test.py

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

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

如果不想使用fixture,当然可以定义一个简单的helper,并在需要的地方使用普通的导入。

根/测试/帮助/ redis.py

class MockRedis():
# stuff

根/测试/材料/ test.py

from helper.redis import MockRedis


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

但是,这里您可能会遇到路径问题,因为模块不在测试的子文件夹中。你应该能够通过向你的helper添加__init__.py来克服这个问题(未测试)

根/测试/帮助/ < >强init.py < / >强

from .redis import MockRedis

或者简单地将helper模块添加到PYTHONPATH中。

我使用conftest.py文件来定义注入到测试中的fixture,这是conftest.py的正确使用吗?

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

它还有其他用途吗?

是的, fixture是以前和有时由pytest运行的函数 之后,实际测试功能。fixture中的代码可以执行任何操作 希望如此。例如,可以使用fixture获取要进行测试的数据集,或者还可以使用fixture在运行测试之前将系统置于已知状态

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

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

第二,是的,你可以在顶级测试目录的子目录中有其他conftest.py文件。如果这样做,在这些较低级的conftest.py文件中定义的fixture将可用于该目录和子目录中的测试。

最后,将fixture放在测试根的conftest.py文件中,将使它们在所有测试文件中可用。

下面是关于使用共享固定装置的官方文档:

conftest.py:跨多个文件共享fixture

conftest.py文件作为一种为整个目录提供fixture的方法。conftest.py中定义的fixture可以被该包中的任何测试使用,而不需要导入它们(pytest将自动发现它们)。

你可以有多个包含测试的嵌套目录/包,并且每个目录都可以有自己的conftest.py和自己的fixture,添加到父目录中conftest.py文件提供的fixture。