在测试中创建和导入帮助器函数,而不使用 py.test 在 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


当前的“解决方案”

我目前正在通过导入我的项目的 test目录(现在是一个包)中的一个模块来做到这一点,但是如果可能的话,我想用其他一些机制来做到这一点(这样我的 test目录中就不会有包,而只有测试,测试可以在安装版本的包上运行,这是建议的 这里是关于良好实践的 py.test 文档)。

37795 次浏览

my option is to create an extra dir in tests dir and add it to pythonpath in the conftest so.

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

in the conftest.py

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

in setup.cfg

[pytest]
norecursedirs=tests/helpers

this module will be available with import utils, only be careful to name clashing.

While searching for a solution for this problem I came across this SO question and ended up adopting the same approach. Creating a helpers package, munging sys.path to make it importable and then just importing it...

This did not seem the best approach, so, I created pytest-helpers-namespace. This plugin allows you to register helper functions on your 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

And then, within a test case function body just use it like

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)

Its pretty simple and the documentation pretty small. Take a look and tell me if it addresses your problem too.

As another option, this directory structure worked for me:

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

And then in my_test.py import the utilities using: from test_helpers import utils

You could define a helper class in conftest.py, then create a fixture that returns that class (or an instance of it, depending on what you need).

import pytest




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




@pytest.fixture
def helpers():
return Helpers

Then in your tests, you can use the fixture:

def test_with_help(helpers):
helpers.help_me()

Create a helpers package in tests folder:

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

in setup.cfg:

[pytest]
norecursedirs=tests/helpers

the helpers will be available with import helpers.

To access a method from different modules without creating packages, and have that function operate as a helper function I found the following helpful:

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")

It is possible that some of you will be completely uphold by my suggestion. However, very simple way of using common function or value from other modules is to inject it directly into a common workspace. Example:
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())