测试代码是不是从 py.test 会话中执行

Posted

技术标签:

【中文标题】测试代码是不是从 py.test 会话中执行【英文标题】:Test if code is executed from within a py.test session测试代码是否从 py.test 会话中执行 【发布时间】:2014-10-01 00:36:55 【问题描述】:

如果我的代码在 py.test 下运行,我想连接到不同的数据库。是否有可以调用的函数或可以测试的环境变量来告诉我是否在 py.test 会话下运行?处理这个问题的最佳方法是什么?

【问题讨论】:

需要更多细节。 py.test,数据库?这些有点通用。 py.test 是测试系统 (pytest.org)。我在 Mongo 的数据库,但我认为它可以是任何数据库。 啊.. 抱歉,我帮不上忙。很高兴你找到了答案。 这个问题得到了反对票,因为它被认为是“不好的做法”。对我来说,我有很多实验,我只想测试它们是否运行没有错误。运行完成所需的时间太长,所以我一直在将“test_mode”参数传递给我想以这种方式测试的每个实验,它只是做了各种事情来缩短实验,同时仍然运行所有代码。这种方法非常重复,而且有点草率,我宁愿只询问系统我是否正在测试。有没有人有比下面接受的更好的解决方案? 【参考方案1】:

我想到了一个更简单的解决方案:

import sys

if "pytest" in sys.modules:
    ...

Pytest 运行程序将始终加载 pytest 模块,使其在 sys.modules 中可用。

当然,此解决方案仅在您尝试测试的代码不使用 pytest 本身时才有效。

【讨论】:

如果你问我,这似乎是一个更清洁/更 Pythonic 的解决方案 更好的答案,也可以用于其他测试框架,例如nose 同样,这是recommended approach for detecting py.test under Django。 警告:我从这种方法中得到误报。在非 pytest 环境中,我在 sys.modules.keys() 看到 pytest。 @duhaime 它在sys.modules 中的唯一方式是它已经以某种方式直接在您的代码中或通过另一个导入(可能有一个库您使用它确实导入它)。正如我所说,“此解决方案仅在您尝试测试的代码不使用 pytest 本身时才有效”。【参考方案2】:

手册中还记录了另一种方法: https://docs.pytest.org/en/latest/example/simple.html#pytest-current-test-environment-variable

Pytest 会设置以下环境变量PYTEST_CURRENT_TEST

检查所述变量的存在应该可靠地允许人们检测代码是否正在从 pytest 的保护伞中执行。

import os
if "PYTEST_CURRENT_TEST" in os.environ:
    # We are running under pytest, act accordingly...

【讨论】:

为我工作。 (在env.py 中,Flask-Migrate==2.5.2 alembic==1.3.3 Flask-SQLAlchemy==2.4.1 SQLAlchemy==1.3.13 pytest==5.3.5) 请注意,此方法仅在运行某些实际测试时有效!在 pytest 收集期间导入模块时,此检测将不起作用!【参考方案3】:

一个解决方案来自RTFM,虽然不是在一个明显的地方。该手册的代码也有错误,在下面更正。

检测是否从 pytest 运行中运行

通常,让应用程序代码表现不同是个坏主意 如果从测试中调用。但如果你绝对必须找出你的 应用程序代码正在从测试中运行,您可以执行类似的操作 这个:

# content of conftest.py
def pytest_configure(config):
    import sys
    sys._called_from_test = True

def pytest_unconfigure(config):
    import sys  # This was missing from the manual
    del sys._called_from_test

然后检查 sys._called_from_test 标志:

if hasattr(sys, '_called_from_test'):
    # called from within a test run
else:
    # called "normally"

相应地在您的应用程序中。使用自己的也是一个好主意 用于处理标志的应用程序模块而不是 sys。

【讨论】:

如果您发现手动代码有错误,请提交补丁。社区会感谢你。 :) 完成。 bitbucket.org/LevIsrael/pytest/pull-request/1/… 文档现在已经更新,即使上面链接的 PR 没有关闭。这可能是因为 pytest 现在在 GitHub 上,而不是 bitbucket。 这可能不起作用 - 在某些情况下 conftest.py 加载得太晚。见github.com/pytest-dev/pytest-django/issues/333【参考方案4】:

使用pytest==4.3.1 上述方法失败,所以我只是去老学校检查:

if 'pytest' in sys.argv[0]:
  print('pytest was called!')

【讨论】:

如果你使用'py.test',这将同时测试any(re.findall(r'pytest|py.test', sys.argv[0])) 好像是在3.2中引入了env变量:docs.pytest.org/en/stable/…但可能在某些版本中被暂时删除了? 我发现这并不总是可靠的。如果您使用 pytest-xdist 包,这将不起作用。不过,模块检查在这种情况下有效 是的,除非您得到我在对该答案建议的评论中描述的误报,否则您绝对应该使用模块方法!【参考方案5】:

这可以通过在测试代码中设置环境变量来完成。例如,给定一个项目

conftest.py
mypkg/
    __init__.py
    app.py
tests/
    test_app.py

test_app.py你可以添加

import os
os.environ['PYTEST_RUNNING'] = 'true'

然后你可以查看app.py

import os
if os.environ.get('PYTEST_RUNNING', '') == 'true':
    print('pytest is running')

【讨论】:

【参考方案6】:

虽然其他答案 (http://pytest.org/latest/example/simple.html#detect-if-running-from-within-a-pytest-run) 中解释的 hack 确实有效,但您可能可以以不需要这样做的方式设计代码。

如果您设计代码以通过连接或其他方式以某种方式将要连接的数据库作为参数,那么您可以在运行测试时注入不同的参数,然后在应用程序驱动它时注入不同的参数。你的代码最终会得到更少的全局状态,更多的模块化和可重用性。所以对我来说,这听起来像是一个测试促使你更好地设计代码的例子。

【讨论】:

您引用的py.test documentation 几乎不是黑客;这是针对常见投诉的官方解决方案。也就是说,trivial one-liner proposed by ramnes 对于大多数用例来说都非常出色。无论如何,What You Want To Do Is Considered Harmful™从来没有是一个有效的解决方案。如果那是你能做的最好的,为什么还要费心回应呢?代码库在运行时检测py.test 有明显的架构原因。 我同意这种担忧。一般来说,如果您编写代码以在测试中运行时表现不同,那么您真的在测试您的代码吗?或者你只是在测试你的测试代码?当您在测试时将代码分支到不同的方向时,您将越来越远离测试工作的精神。 #meta

以上是关于测试代码是不是从 py.test 会话中执行的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法指定从文件运行哪些 pytest 测试?

在 py.test 中的每个测试之前和之后运行代码?

py.test 不从数据库中提取数据

如何配置 PyCharm 以运行 py.test 测试?

py.test :可以在测试功能级别应用多个标记吗?

Py.test 失败,但 ./manage.py 测试工作正常