跳过主要内容

pytest用于测试控制台脚本的插件

项目描述

pytest-console-scripts

PyPI PyPI - License GitHub Workflow Status codecov

GitHub issues GitHub pull requests GitHub commits since latest release (by date)

pytest-console-scripts是一个pytest插件,用于在测试中运行Python脚本。它与subprocess.run()非常相似,但它还有一个进程内模式,其中脚本由运行pytest的解释器执行(使用一些沙盒技术)。

进程内模式显著减少了运行许多外部脚本的测试套件的运行时间。这加快了开发速度。在CI环境中,可以使用子进程模式确保脚本在由新解释器运行时也能正常工作(并且表现相同)。

需求

  • Python 3.8+,或PyPy3
  • Pytest 4.0或更高版本

安装

您可以通过从pip(位于PyPI)安装 "pytest-console-scripts"。

$ pip install pytest-console-scripts

通常,您会将它添加到 tox.ini 文件中的测试依赖项中(参见tox 文档)。

使用方法

此插件将运行通过 setup.py 中的 console_scripts 入口点安装的脚本、当前目录中的 Python 文件(或指定路径下的任何地方,如果提供了路径),以及路径中任何其他位置的 Python 脚本。它还将运行非 Python 脚本的可执行文件,但仅在子进程模式下(对于此目的使用 pytest-console-scripts 没有好处,您应仅使用 subprocess.run)。

以下是一个具有 console_scripts 入口点的示例。假设我们有一个名为 foo 的 Python 包,其 setup.py 如下所示:

setup(
    name='foo',
    version='0.0.1',
    py_modules=['foo'],
    entry_points={
        'console_scripts': ['foobar=foo:bar']
    },
)

我们可以使用 pytest-console-scripts 来测试 foobar 脚本。

def test_foo_bar(script_runner):
    result = script_runner.run(['foobar', '--version'])
    assert result.returncode == 0
    assert result.stdout == '3.2.1\n'
    assert result.stderr == ''

    script_runner.run('foobar --version', shell=True, check=True)

这将使用插件提供的 script_runner 修复件来运行脚本并捕获其输出。

script_runner.run 的参数是脚本的命令名以及要传递给它的任何命令行参数。此外,还可以使用以下关键字参数:

  • cwd - 设置测试脚本的工作目录。
  • env - 一个字典,其中包含要使用而不是当前环境的环境变量。
  • stdin - 一个文件-like 对象,它将被管道传输到脚本的标准输入。
  • check - 如果 returncode != 0,则引发异常,默认为 False。
  • shell - 模拟 shell 执行,这对于简单情况应该效果良好,默认为 False。

也支持类型提示。您可以使用以下代码为修复件提供类型提示

from pytest_console_scripts import ScriptRunner

def test_foo_bar(script_runner: ScriptRunner) -> None:
    ...

配置脚本执行模式

在上面的示例中,foobar 脚本将以进程内模式运行(这是默认值)。这很快,适用于开发过程中的快速迭代。当我们对功能感到满意后,就到了运行脚本以模拟真实调用的子进程模式的时候了。有多种方法可以实现这一点。我们可以通过 pytest 配置来配置它(例如在 tox.ini 中)

[pytest]
script_launch_mode = subprocess

我们可以向 pytest 提供命令行选项(这将覆盖配置文件)

$ pytest --script-launch-mode=subprocess test_foobar.py

我们还可以标记单个测试以在特定模式下运行

@pytest.mark.script_launch_mode('subprocess')
def test_foobar(script_runner):
    ...

在这三种方法中,测试的标记优先于命令行选项,而命令行选项又覆盖了配置设置。所有三种都可以采取三种可能值:"inprocess"、"subprocess" 和 "both"(这将导致测试两次运行:一次在进程内模式,一次在子进程模式下)。

与模拟的交互

当使用 pytest-console-scripts 运行时,可以在控制台脚本内部模拟对象和函数,但仅限于进程内模式。当脚本以子进程模式运行时,它将由单独的 Python 解释器执行,并且测试无法在其中模拟任何内容。

模拟的另一个限制是,对于没有通过console_scripts 入口点安装的简单 Python 脚本,主脚本中对象内部的对象模拟将不起作用。原因是我们使用 $ python myscript.py 运行 myscript.py 时,脚本被导入到 __main__ 命名空间,而不是 myscript 命名空间。我们针对 myscript.myfunction 的修补将不会影响在 __main__ 命名空间中调用在相同文件中定义的 myfunction 时,该代码所看到的内容。

有关如何解决此问题的想法,请参阅此 stackoverflow 回答

抑制脚本运行结果的打印

当涉及 pytest-console-scripts 的测试失败时,查看在其中执行的脚本的输出通常非常有用。我们试图提供帮助,并在返回 script_runner.run() 的结果之前打印出来。通常情况下,PyTest 捕获 测试运行期间的所有输出,除非某些测试失败,否则不会显示给用户。这正是我们想要的。

然而,在某些情况下,禁用输出捕获可能很有用,PyTest 提供了 方法 来实现这一点。当捕获被禁用时,所有测试运行结果都将被打印出来,这可能会使得检查其他测试输出变得更加困难。为了处理这个问题,pytest-console-scripts 有一个选项可以禁用脚本运行结果的打印。

$ pytest --hide-run-results test_foobar.py

也可以仅针对一次脚本运行禁用它。

result = script_runner.run('foobar', print_result=False)

当禁用脚本运行结果的打印时,即使测试失败,脚本输出也不会可见。遗憾的是,没有自动打印仅在测试失败时的方式,因为当脚本运行完成时,我们并不知道测试是否会失败。可以从测试中手动执行,使用以下方法:

result.print()

结合 --hide-run-resultsprint_result=False,可以在捕获关闭时仅打印有趣的运行结果。

开发和测试中的包安装

由于 pytest-console-scripts 依赖于脚本位于路径中,它只能运行已安装(如果你对去除这个限制感兴趣,请查看 这个工单 以及特别是 这个评论)的包的控制台脚本。如果你想快速地在开发期间运行测试,额外的安装步骤将增加显著的开销并减慢你的速度。

有一种方法可以解决这个问题:使用 pip install -e .开发模式 安装你的包。如果你使用 tox,你可以使用其中一个现有的虚拟环境(它们位于 .tox/ 中)。否则,创建一个仅用于开发的 虚拟环境,激活它并运行 python setup.py develop 以开发模式安装你的包。每次你添加一个新的控制台脚本时,都需要重新安装,但除此之外,所有代码的更改都将立即被测试捕获。

贡献

欢迎贡献。可以使用 tox 运行测试,请在提交拉取请求之前确保覆盖率至少保持不变。

许可证

MIT 许可证的条款下分发,"pytest-console-scripts" 是免费和开源软件。

问题

如果你遇到任何问题,请 提交问题 并附带详细描述。


Pytest-console-scripts 是使用 Cookiecutter 以及 @hackebrot's Cookiecutter-pytest-plugin 模板最初生成的。

项目详情


下载文件

下载适合您平台的文件。如果您不确定选择哪个,请了解更多关于 安装包 的信息。

源代码分发

pytest-console-scripts-1.4.1.tar.gz (21.0 kB 查看哈希值)

上传时间 源代码

构建分发

pytest_console_scripts-1.4.1-py3-none-any.whl (10.9 kB 查看哈希值)

上传时间 Python 3

由以下支持