七、pytest -- 捕获标准输出和标准错误输出

1. 标准输出/标准错误输出/标准输入的默认捕获行为

在测试执行期间,任何标准输出和标准错误输出都将会被捕获;若是测试失败或者发生异常,异常信息的堆栈也将一同显示,你能够经过--show-capture命令行选项来自定义这些行为;git

--show-capture的配置项能够为:no,stdout,stderr,log,all,默认是allgithub

另外,标准输入被设置为一个"null"对象。由于在自动化测试中,不多须要使用到交互输入的场景;缓存

实际上,当咱们想要使用标准输入时,会获得一个错误:OSError: reading from stdin while output is capturedbash

一般状况下,捕获行为是经过拦截对低级别文件描述符的写入操做来实现的。这就使得咱们能够捕获简单的print()语句以及测试中子程序的输出行为;函数

2. 修改和去使能捕获行为

pytest有两种捕获行为,能够经过--capture命令行选项来指定;测试

2.1. 文件描述符级别的捕获行为(默认)

全部向操做系统的文件描述符1(标准输入)和2(标准错误输入)的写入行为都会被捕获,这个也是pytest的默认捕获行为,也能够经过--capture=fd来指定;ui

文件描述符是与当前进程打开的文件相对应的小整数。例如,标准输入的文件描述符一般是0,标准输出的是1,标准错误的是2,以后被进程打开的文件的描述符依次指定为三、四、5等。操作系统

2.2. sys级别的捕获行为

只有向Pythonsys.stdoutsys.stderr的写入行为会被捕获,不执行对文件描述符的写入的捕获,经过--capture=sys来指定;命令行

2.3. 去使能捕获行为

经过--capture=no能够去使能pytest的捕获行为;

也能够经过-s命令行选项实现相同的效果,它只是--capture=no的一个快捷方式,本质上是同样的;

3. 使用print()函数调试用例

默认的捕获行为带来的一个主要的好处是,就是可使用print()函数帮助调试用例;

咱们来看下面这个例子:

# src/chapter-7/test_module.py

def setup_function(function):
    print("setting up", function)


def test_func1():
    assert True


def test_func2():
    assert False

setup_function(function)函数会在每一个测试用例开始以前执行,作一些初始化的操做;

如今,咱们来执行这个模块:

λ pipenv run pytest -q src/chapter-7/test_module.py
.F                                                      [100%] 
========================== FAILURES ========================== 
_________________________ test_func2 _________________________

    def test_func2():
>       assert False
E       assert False

src\chapter-7\test_module.py:32: AssertionError
------------------- Captured stdout setup -------------------- 
setting up <function test_func2 at 0x000001F35E76C158>
1 failed, 1 passed in 0.05s

能够看到,pytest会把失败的用例信息精确的打印出来,而且会忽略其余的用例;

4. 在测试用例中访问捕获到的信息

咱们能够经过capsyscapsysbinarycapfdcapfdbinary fixtures来访问测试执行过程当中产生的输出信息;

下面这个例子用于检查测试中的输出信息:

# src/chapter-7/test_output.py

import sys


def test_output(capsys):
    print('hello')
    print('world', file=sys.stderr, end='&')  # 标准错误输出,修改结束符
    captured = capsys.readouterr()
    assert captured.out == 'hello\n'  # print() 默认的结束符是换行符
    assert captured.err == 'world&'
    print('next')
    captured = capsys.readouterr()
    assert captured.out == 'next\n'

readouterr()方法会返回一个命名元组(包含outerr属性),表示到目前为止全部的标准输出和标准错误输出,而后重置缓存区

若是你想访问文件描述符级别的测试输出,可使用capfd fixture,它提供了彻底相同的接口;

若是想访问的是非文本型的数据,可使用capsysbinary fixture,它的readouterr()方法返回的是字节流,参考下面的例子:

# src/chapter-7/test_output.py

def test_binary_output(capsysbinary):
    print('hello')
    captured = capsysbinary.readouterr()
    assert captured.out == b'hello\n'

若是你想临时的去使能捕获行为,可使用capsys.disabled()方法,它做为一个上下文管理器来使用,能够禁止with做用域中的捕获行为,参考下面的例子:

# src/chapter-7/test_output.py

def test_disabling_capturing(capsys):
    print("hello")
    with capsys.disabled():
        print("world")
    captured = capsys.readouterr()
    assert captured.out == "hello\n"

GitHub仓库地址:https://github.com/luizyao/pytest-chinese-doc