1. 標准輸出/標准錯誤輸出/標准輸入的默認捕獲行為
在測試執行期間,任何標准輸出和標准錯誤輸出都將會被捕獲;如果測試失敗或者發生異常,異常信息的堆棧也將一同顯示,你可以通過--show-capture
命令行選項來自定義這些行為;
--show-capture
的配置項可以為:no,stdout,stderr,log,all
,默認是all
;
另外,標准輸入被設置為一個"null"
對象。因為在自動化測試中,很少需要使用到交互輸入的場景;
實際上,當我們想要使用標准輸入時,會得到一個錯誤:
OSError: reading from stdin while output is captured
;
通常情況下,捕獲行為是通過攔截對低級別文件描述符的寫入操作來實現的。這就使得我們可以捕獲簡單的print()
語句以及測試中子程序的輸出行為;
2. 修改和去使能捕獲行為
pytest
有兩種捕獲行為,可以通過--capture
命令行選項來指定;
2.1. 文件描述符級別的捕獲行為(默認)
所有向操作系統的文件描述符1(標准輸入)和2(標准錯誤輸入)的寫入行為都會被捕獲,這個也是pytest
的默認捕獲行為,也可以通過--capture=fd
來指定;
文件描述符是與當前進程打開的文件相對應的小整數。例如,標准輸入的文件描述符通常是0,標准輸出的是1,標准錯誤的是2,之后被進程打開的文件的描述符依次指定為3、4、5等。
2.2. sys
級別的捕獲行為
只有向Python
的sys.stdout
和sys.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. 在測試用例中訪問捕獲到的信息
我們可以通過capsys
、capsysbinary
、capfd
和capfdbinary 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()
方法會返回一個命名元組(包含out
和err
屬性),表示到目前為止所有的標准輸出和標准錯誤輸出,然后重置緩存區;
如果你想訪問文件描述符級別的測試輸出,可以使用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"