使用 py.test 在测试中创建和导入辅助函数而不在测试目录中创建包

Create and import helper functions in tests without creating packages in test directory using py.test

问题

如何在不在 test 目录中创建包的情况下在测试文件中导入辅助函数?


上下文

我想创建一个可以在多个测试中导入的测试辅助函数。比如说,像这样:

# In common_file.py

def assert_a_general_property_between(x, y):
    # test a specific relationship between x and y
    assert ...


# In test/my_test.py

def test_something_with(x):
    some_value = some_function_of_(x)
    assert_a_general_property_between(x, some_value)

使用 Python 3.5,使用 py.test 2.8.2


当前"solution"

我目前通过在项目的 test 目录(现在是一个包)中导入一个模块来做到这一点,但如果可能的话,我想用其他机制来做到这一点(这样我的test 目录没有包,只有测试,并且测试可以 运行 在已安装的包版本上,推荐 here in the py.test documentation on good practices).

我的选择是在 tests 目录中创建一个额外的目录,并将其添加到 conftest 中的 pythonpath 中。

tests/
    helpers/
      utils.py
      ...
    conftest.py
setup.cfg

conftest.py

import sys
import os
sys.path.append(os.path.join(os.path.dirname(__file__), 'helpers'))

setup.cfg

[pytest]
norecursedirs=tests/helpers

此模块将在 import utils 中可用,只是要注意名称冲突。

在寻找此问题的解决方案时,我遇到了这个 SO 问题,并最终采用了相同的方法。创建一个助手包,修改 sys.path 使其可导入,然后只导入它...

这似乎不是最好的方法,所以,我创建了 pytest-helpers-namespace。此插件允许您在 conftest.py:

上注册辅助函数
import pytest

pytest_plugins = ['helpers_namespace']

@pytest.helpers.register
def my_custom_assert_helper(blah):
    assert blah

# One can even specify a custom name for the helper
@pytest.helpers.register(name='assertme')
def my_custom_assert_helper_2(blah):
    assert blah

# And even namespace helpers
@pytest.helpers.asserts.register(name='me')
def my_custom_assert_helper_3(blah):
    assert blah

然后,在测试用例函数体中像

一样使用它
def test_this():
    assert pytest.helpers.my_custom_assert_helper(blah) 

def test_this_2():
    assert pytest.helpers.assertme(blah)

def test_this_3():
    assert pytest.helpers.asserts.me(blah)

它非常简单,文档也很小。看看它是否也能解决您的问题。

作为另一种选择,这个目录结构对我有用:

mypkg/
    ...
test_helpers/
    __init__.py
    utils.py  
    ...
tests/
    my_test.py
    ...

然后在 my_test.py 中使用以下命令导入实用程序: from test_helpers import utils

您可以在 conftest.py 中定义一个助手 class,然后创建一个 returns class 的夹具(或它的一个实例,具体取决于您的需要).

import pytest


class Helpers:
    @staticmethod
    def help_me():
        return "no"


@pytest.fixture
def helpers():
    return Helpers

然后在你的测试中,你可以使用夹具:

def test_with_help(helpers):
    helpers.help_me()

在测试文件夹中创建一个助手包:

tests/
    helpers/
      __init__.py
      utils.py
      ...
    # make sure no __init__.py in here!
setup.cfg

在setup.cfg中:

[pytest]
norecursedirs=tests/helpers

助手将在 import helpers 时可用。

要在不创建包的情况下访问不同模块的方法,并让该函数作为辅助函数运行,我发现以下内容很有帮助:

conftest.py:

@pytest.fixture
def compare_test_vs_actual():
    def a_function(test, actual):
        print(test, actual)
    return a_function

test_file.py:

def test_service_command_add(compare_test_vs_actual):
    compare_test_vs_actual("hello", "world")

你们中的一些人可能会完全支持我的建议。然而,使用来自其他模块的通用函数或值的非常简单的方法是将其直接注入到通用工作区中。示例:
conftest.py:

import sys

def my_function():
   return 'my_function() called'

sys.modules['pytest'].common_funct = my_function

test_me.py

import pytest

def test_A():
   print(pytest.common_funct())