如何用自定义字符串完全替换pytest输出以进行测试?

时间:2019-02-11 23:06:06

标签: python subprocess pytest

场景

我正在编写一个程序包,该程序包要求我从通过pytest运行的pytest内部调用subprocess。因此,显然,从子流程捕获的输出正是我要显示的错误,因为它具有pytest提供的所有出色的格式和信息。不幸的是,当前主要的pytest调用仅显示包装器的内部代码,而不是漂亮的子进程输出,在我将其输出后,仅显示在pytest的捕获的stdout部分中。 我想格式化输出以查找失败和错误,就像直接调用代码一样,并隐藏进行了子流程调用的过程。因此,我基本上想用一个不同的字符串完全替换一个测试函数的输出。这可能吗?

MWE

让我们看一下一个简单的包装函数的MWE(没有做任何有用的事情,但是我能想到的最短的MWE):

import functools
import json
from subprocess import Popen, PIPE
import sys


def call_something(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        # for the sake of simplicity, a dummy call
        p = Popen([sys.executable, '-c', 'import numby'], stderr=PIPE, stdout=PIPE)
        # let's imagine this is the perfect string output we want
        # to print instead of the actual output generated from...
        error = p.communicate()[1].decode("utf-8")

        if p.returncode != 0:
            # ... this line
            raise AssertionError(f'{error}')

    return wrapper

@call_something
def test_something():
    assert 1 == 2

您可以看到我有test_something()函数,该函数在子进程中将失败。

电流输出

如果我使用此文件运行pytest,则会得到:

================================== FAILURES ===================================
_______________________________ test_something ________________________________

func = <function test_something at 0x000001EA414F1400>, args = (), kwargs = {}
p = <subprocess.Popen object at 0x000001EA414A67B8>
error = 'Traceback (most recent call last):\r\n  File "<string>", line 1, in <module>\r\nModuleNotFoundError: No module named \'numby\'\r\n'

    def wrapper(*args, **kwargs):
        # for the sake of simplicity, a dummy call
        p = Popen([sys.executable, '-c', 'import numby'], stderr=PIPE, stdout=PIPE)
        # let's imagine this is the perfect string output we want
        # to print instead of the actual output generated from...
        error = p.communicate()[1].decode("utf-8")

        if p.returncode != 0:
            # ... this line
>               raise AssertionError(f'{error}')
E               AssertionError: Traceback (most recent call last):
E                 File "<string>", line 1, in <module>
E               ModuleNotFoundError: No module named 'numby'

test_me.py:18: AssertionError
========================== 1 failed in 0.18 seconds ===========================

很显然,我不想显示包装函数的详细信息。代替

所需的输出

我想展示子过程中发生的情况。因此它应该看起来像这样(或类似)。

================================== FAILURES ===================================
_______________________________ test_something ________________________________

<string captured from subprocess>
========================== 1 failed in 0.11 seconds ===========================

所以我的问题要小一些:

简短的问题

  • 如何使用自定义字符串替换pytest输出以进行测试 从我的包装纸上来?

1 个答案:

答案 0 :(得分:0)

在引发错误时,可以使用from语法来抑制或更改异常的链接方式。例如,考虑以下内容:

try:
    a / b
except ZeroDivisionError:
    raise ValueError('Invalid b value')

如果ZeroDivisionError后跟b == 0,则会显示ValueError,但是您可能想隐藏ZeroDivisionError,因为唯一相关的部分是{{ 1}}。因此,您应该写:

ValueError

这只会显示try: a / b except ZeroDivisionError: raise ValueError('Invalid b value') from None ,告诉您ValueError错误

您还可以使用b语法进行其他操作,这在这里将是相关的,有关详细信息,请参见this thread

我通过抑制奇怪的管道错误并提高from来完成与您尝试的操作类似的操作:

ModuleNotFoundError

请注意此处使用# Test if <module> is callable try: sp.run('<run some module>', shell=True, check=True, stdout=sp.PIPE) except sp.CalledProcessError as exc: raise ModuleNotFoundError( '<some module> not working. Please ensure it is installed and can be called with the command: <command>' ) from exc