如何将脚本作为pytest测试运行

亚努斯

假设我有一个用assert-statements表示为简单脚本的测试(请参阅背景了解原因),例如

import foo
assert foo(3) == 4

我如何以一种不错的方式将该脚本包含在pytest测试套件中?

我尝试了两种可行但不那么精妙的方法:

一种方法是像测试一样命名脚本,但这会使整个pytest发现在测试失败时失败。

我当前的方法是从测试函数中导入脚本:

def test_notebooks():
    notebook_folder = Path(__file__).parent / 'notebooks'
    for notebook in notebook_folder.glob('*.py'):
        import_module(f'{notebook_folder.name}.{notebook.stem}')

这可以工作,但是不会单独报告脚本,并且测试失败的堆栈跟踪时间长且蜿蜒:

__________________________________________________ test_notebooks ___________________________________________________

    def test_notebooks():
        notebook_folder = Path(__file__).parent / 'notebooks'
        for notebook in notebook_folder.glob('*.py'):
>           import_module(f'{notebook_folder.name}.{notebook.stem}')

test_notebooks.py:7:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
envs\anaconda\lib\importlib\__init__.py:127: in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
<frozen importlib._bootstrap>:1006: in _gcd_import
... (9 lines removed)...
<frozen importlib._bootstrap>:219: in _call_with_frames_removed
    ???
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

>   assert False
E   AssertionError

notebooks\notebook_2.py:1: AssertionError

背景

我在脚本文件中进行测试的原因是,它们实际上是Jupyter笔记本.py,由出色的jupytext插件另存为带有标记的-files

这些笔记本将转换为html进行文档编制,可以交互方式用于学习系统,并用作廉价的功能测试。

马蹄铁

在测试功能中执行脚本

从测试函数调用脚本没有错,因此您的方法非常好。但是,我将使用参数化,而不是在for循环中运行脚本。这样,您可以使每个脚本很好地执行一次测试。如果您不喜欢冗长的回溯,则可以在自定义的pytest_exception_interacthookimpl中进行裁剪。例:

# conftest.py

def pytest_exception_interact(node, call, report):
    excinfo = call.excinfo
    if 'script' in node.funcargs:
        excinfo.traceback = excinfo.traceback.cut(path=node.funcargs['script'])
    report.longrepr = node.repr_failure(excinfo)

参数化测试:

# test_spam.py

import pathlib
import runpy
import pytest

scripts = pathlib.Path(__file__, '..', 'scripts').resolve().glob('*.py')


@pytest.mark.parametrize('script', scripts)
def test_script_execution(script):
    runpy.run_path(script)

测试执行收益率(为了进行测试,我使用诸如assert False或的单行创建了简单的脚本1 / 0

$ pytest -v
======================================= test session starts ========================================
platform linux -- Python 3.6.8, pytest-4.6.3, py-1.8.0, pluggy-0.12.0 -- /home/hoefling/projects/.venvs/stackoverflow/bin/python3.6
cachedir: .pytest_cache
rootdir: /home/hoefling/projects/private/stackoverflow/so-56807698
plugins: mock-1.10.4, cov-2.7.1, forked-1.0.2, xdist-1.28.0, django-3.4.8
collected 3 items                                                                                  

test_spam.py::test_script_execution[script0] PASSED
test_spam.py::test_script_execution[script1] FAILED
test_spam.py::test_script_execution[script2] FAILED

============================================= FAILURES =============================================
____________________________________ test_script_runpy[script1] ____________________________________

>   assert False
E   AssertionError

scripts/script_3.py:1: AssertionError
____________________________________ test_script_runpy[script2] ____________________________________

>   1 / 0
E   ZeroDivisionError: division by zero

scripts/script_2.py:1: ZeroDivisionError
================================ 2 failed, 1 passed in 0.07 seconds ================================

定制测试协议

如果您不喜欢上述解决方案,那么我想到的另一件事是实现自己的测试收集和执行协议。例:

# conftest.py

import pathlib
import runpy
import pytest


def pytest_collect_file(parent, path):
    p = pathlib.Path(str(path))
    if p.suffix == '.py' and p.parent.name == 'scripts':
        return Script(path, parent)


class Script(pytest.File):
    def collect(self):
        yield ScriptItem(self.name, self)


class ScriptItem(pytest.Item):
    def runtest(self):
        runpy.run_path(self.fspath)

    def repr_failure(self, excinfo):
        excinfo.traceback = excinfo.traceback.cut(path=self.fspath)
        return super().repr_failure(excinfo)

这将收集目录中的每个.py文件scripts,将每个脚本包装在测试用例中,并runpy在测试执行时调用执行日志看起来几乎相同,只是测试的名称不同。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

将QuickTests作为LoadRunner测试运行

如何将函数名称传递给测试运行器?

如何将参数从 Gradle 插件传递到 JUnit4 测试运行器?

如何更改测试运行超时?

在将应用程序作为TestNG测试运行时破坏测试用例

如何将Parameterized JUnit测试运行器与使用Spring注入的字段一起使用?

pytest测试运行jupyter笔记本

如何防止Android Gradle构建将设备测试作为单元测试运行

如何在Android Studio中将测试方法或类作为Android测试运行

当我“将Spring作为JUnit测试运行”时,内部会发生什么?

如何检测我的python脚本/代码是否从python单元测试运行?

如何从TFS到Powershell脚本获取最后的测试运行ID

如何使用dotnet测试运行特定测试?

如何阻止 Jenkins 将良好的测试运行标记为错误?

将python测试运行信息导入sonarqube

如何自动重命名Testrail中的测试运行

如何测试运行命令的Go函数?

如何强制Google基准测试运行多个迭代?

如何使我的Maven集成测试运行

如何通过Mocha测试运行时参数?

如何按顺序制作junit测试运行方法

如何测试运行SQL查询的方法

如何为C ++程序创建测试运行/计划?

如何使用Vividus工具同步测试运行?

如何测试运行非主要方法?[Java,IntelliJ]

我想使用空手道将每个.feature文件作为单个TestNG测试运行?

在测试运行开始时动态选择pytest测试

如何在 Python 脚本中的 leetcode 测试运行器中表示这些单链表节点?

如何在Team Build 2013 Post-Test脚本中检测测试运行是否成功?