在不同的进程中运行py.test测试

Dik*_*rAz 5 python pytest tensorflow

我正在尝试测试tensorflow程序。我正在使用参数化的py.test夹具设置tensorflow会话:

@pytest.fixture(scope="session", params=configuration)
def session(request):
    if request.param == 'tensorflow':
        return tf.Session()
    elif request.param == 'tensorflow-eager':
        tfe.enable_eager_execution()
        return tf.Session()
    elif ...
Run Code Online (Sandbox Code Playgroud)

Tensorflow具有全局状态,因此一些测试启动会污染它。例如,启用急切执行后,无法禁用它。有没有一种方法可以指示py.test为每个测试创建一个新进程?还是使用参数化夹具来配置测试环境的另一种方法?用法示例:

@pytest.mark.parametrize("bias_type", ['variable', 'ndarray', 'list', 'tuple'])
@pytest.mark.parametrize("kernel_type", ['variable', 'ndarray', 'list', 'tuple'])
@pytest.mark.parametrize("input_type", ['variable', 'ndarray', 'list', 'tuple'])
def test_convolution(session, input_type, kernel_type, bias_type):
    ...
Run Code Online (Sandbox Code Playgroud)

hoe*_*ing 6

正如评论中所建议的,使用pytest-xdist将是解决方案。该插件专为并行或分布式执行测试而设计(甚至可以进行多平台执行),但非常适合满足您在单独进程中运行每个测试的请求 - 您可以通过--forked参数实现这一点。

免责声明

--forked参数在 Windows 上不起作用,因为 Windows 不支持 fork-exec 模型并且不提供fork().

快速演示

让我们定义一个fixture,它会在运行每个测试之前尝试打开eager execution:

from tensorflow.contrib.eager.python import tfe

import pytest


@pytest.fixture(scope='function', autouse=True)
def eager(request):
    tfe.enable_eager_execution()
Run Code Online (Sandbox Code Playgroud)

这个夹具显然会使所有测试失败,但第一个测试失败,因为急切执行只能转一次。通过一些虚拟测试:

def test_spam():
    assert True

def test_eggs():
    assert True

def test_bacon():
    assert True
Run Code Online (Sandbox Code Playgroud)

pytest按预期运行普通失败:

$ pytest -v
============================== test session starts ================================
platform darwin -- Python 3.6.3, pytest-3.3.1, py-1.5.2, pluggy-0.6.0 -- /Users/hoefling/.virtualenvs/stackoverflow/bin/python3.6
cachedir: .cache
rootdir: /Users/hoefling/projects/private/stackoverflow/so-48234032, inifile:
plugins: forked-0.2, mock-1.6.3, hypothesis-3.44.4
collected 3 items

test_spam.py::test_spam PASSED                                                [ 33%]
test_spam.py::test_eggs ERROR                                                 [ 66%]
test_spam.py::test_bacon ERROR                                                [100%]

...
E       ValueError: Do not call tfe.enable_eager_execution more than once in the
same process. Note eager-mode methods such as tfe.run() also call 
tfe.enable_eager_execution.
...
Run Code Online (Sandbox Code Playgroud)

现在安装pytest-xdist

$ pip install pytest-xdist
Run Code Online (Sandbox Code Playgroud)

并重新运行测试:

$ pytest -v --forked
============================== test session starts ================================
platform darwin -- Python 3.6.3, pytest-3.3.1, py-1.5.2, pluggy-0.6.0 -- /Users/hoefling/.virtualenvs/stackoverflow/bin/python3.6
cachedir: .cache
rootdir: /Users/hoefling/projects/private/stackoverflow/so-48234032, inifile:
plugins: forked-0.2, xdist-1.22.0, mock-1.6.3, hypothesis-3.44.4
collected 3 items

test_spam.py::test_spam PASSED                                                [ 33%]
test_spam.py::test_eggs PASSED                                                [ 66%]
test_spam.py::test_bacon PASSED                                               [100%]

============================= 3 passed in 6.09 seconds ============================
Run Code Online (Sandbox Code Playgroud)

测试仍然按顺序运行,但每个测试都在自己的子进程中,因此它们都不会失败。

现在您可以开始尝试并行执行,例如

$ pytest -v --forked --numprocesses=auto
Run Code Online (Sandbox Code Playgroud)

等。有关更多信息和更多使用示例,请参阅插件文档

  • 如果这是在不支持 `--forked` 的 Windows 上怎么办? (2认同)